我正在尝试编写一个 bash 脚本来提示用户输入文件名,如果文件存在,则允许他们覆盖或附加文件。出于某种原因,尽管出现了问题,但我还是不断收到语法错误。不幸的是,我对 Bash 的熟悉程度不如对 Python 的熟悉程度,我发现自己混淆了两者的语法。不过,请参见下文:
#!/bin/bash
echo "Please enter the name of your destination file: "
read destFile
if [ -f "$destFile" ]; then
echo "This file exists."
fi
echo "Please enter the name of your source file: "
read sourceFile
echo "Do you want to 1) Overwrite, 2) Append, 3) Exit?"
echo "Please select your option: "
options=("Overwrite" "Append" "Exit")
while [ -e "$sourceFile" ]; do
select opt in "${options[@]}"; do
case "$opt" in
"Overwrite")
cp "$sourceFile" "$destFile"
echo "Copy Completed."
;;
"Append" )
cat "$sourceFile" >> "$destFile"
echo "Append Completed."
;;
"Exit" )
echo "Script Terminated"
break
;;
esac
break
done
done
答案1
正如您所说,您要解决的问题是(强调):
我正在尝试编写一个 bash 脚本来提示用户输入文件名,并且如果文件存在,允许他们覆盖或附加该文件。
奇怪的是,脚本中检查文件是否存在的代码并未使用if
,尽管它可能应该使用。相反,它使用while
:
while [ -e "$sourceFile" ]; do
这是一个循环。如果源文件存在,则循环内的所有内容,直到匹配的
done
脚本最后一行的 运行。这是一个while
循环,因此运行后将再次执行第一次测试。如果文件仍然存在,则循环主体再次运行,依此类推。
但是循环体中的任何内容都不会导致文件停止存在。四种可能性是:
用户输入 a
1
,源文件将被复制到目标文件上。它是复制的,而不是移动的,因此源文件仍然存在,并且名称相同。用户输入 a
2
,源文件的内容将附加到目标文件。但是,源文件不会被删除;它仍在那里。用户输入 a
3
并Script Terminated
打印一条消息。紧接着是break
命令。这将打破结构。运行时获得的select
摘要仅提到它打破了、或循环,因此您可能希望它打破外层循环。但是,运行时获得的 摘要澄清了这个问题:break
help break
for
while
until
while
select
help select
每次选择后都会执行命令,直到执行中断命令为止。
用户输入了除
1
、2
或 之外的任何内容3
。因此,所有情况均不运行。break
之后的第二个命令esac
将运行。这也破坏了select
构造,不是循环while
,然后while
循环再次运行。
select
实际上是循环。您的break
命令中断的是select
而不是外层while
。根据您提供的问题描述,您几乎肯定没有任何理由使用外层循环。因此,一个好的解决方案就是将外部while
改为if
。为此,您还需要:
- 将其
do
改为then
。 - 将其
done
改为fi
。
如果您选择此解决方案,那么您还需要移动当前拥有的一些命令外部(应该while
是if
),以便它们位于其中。现在,即使实际上不执行任何操作,也会提示用户选择一个选项。仅将 更改为while
(if
并进行其他两个必要的更改才能使其正常工作)无法修复该额外的错误。
另一种解决方案是让脚本在[ -e "$sourceFile" ]
为 false 时提前退出。一种方法是:
[ -e "$sourceFile" ] || exit
另外,如果您喜欢使用if
,则是:
if ! [ -e "$sourceFile" ]; then
exit
fi
如果你使用其中任何一个,那么其余的代码——你打算只在源文件存在时运行的代码——就不需要包含在任何控制结构。请注意,您仍然希望将其放在提示用户采取什么操作的命令之前,而不是之后。
请注意可以break
通过将命令替换为 来“修复”代码exit
。您还可以通过向 传递数字参数来“修复”代码,以break
告诉它要跳出多少层嵌套(大多数语言的break
命令不支持这一点,但 Bash 的命令支持)。但是,我建议不要使用这两种方法——除非只是为了尝试——因为这样会增加代码的复杂性,而这些复杂性应该通过简化代码来解决。目前,您正在while
对某些循环毫无意义的地方使用循环,因此,无论您如何解决问题,都应该采用一种可以简化代码的方法,而不必这样做。
另一方面,如果你真的做想要让整个过程重复进行,那么您应该考虑什么条件会有意义地中断您的外循环。例如,也许您打算在外循环的每次迭代中提示输入源文件和目标文件。如果是这样,那么您需要更改代码来执行此操作。
最后,我建议以这样的方式缩进代码:当控制结构跨越多行时,打开它的行和关闭它的行以相同的级别缩进,而它里面的行(除非在偶尔无法这样做的情况下)缩进更多。这样,你就会知道哪个fi
匹配哪个if
,哪个done
匹配哪个while
/ until
/ for
/ select
,哪个esac
匹配哪个case
。通过更容易地识别,你还可以更好地识别何时需要关键字丢失的,通过以一致的方式缩进内容,您将能够更好地识别脚本的逻辑是否与您的意图不同。