使用选项菜单覆盖/附加目标文件的 Bash 脚本

使用选项菜单覆盖/附加目标文件的 Bash 脚本

我正在尝试编写一个 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循环,因此运行后将再次执行第一次测试。如果文件仍然存在,则循环主体再次运行,依此类推。

但是循环体中的任何内容都不会导致文件停止存在。四种可能性是:

  1. 用户输入 a 1,源文件将被复制到目标文件上。它是复制的,而不是移动的,因此源文件仍然存在,并且名称相同。

  2. 用户输入 a 2,源文件的内容将附加到目标文件。但是,源文件不会被删除;它仍在那里。

  3. 用户输入 a3Script Terminated打印一条消息。紧接着是break命令。这将打破结构。运行时获得的select摘要仅提到它打破了、或循环,因此您可能希望它打破外层循环。但是,运行时获得的 摘要澄清了这个问题:breakhelp breakforwhileuntilwhileselecthelp select

    每次选择后都会执行命令,直到执行中断命令为止。

  4. 用户输入了除12或 之外的任何内容3。因此,所有情况均不运行。break之后的第二个命令esac将运行。这也破坏了select构造,不是循环while,然后while循环再次运行。

select实际上是循环。您的break命令中断的是select而不是外层while。根据您提供的问题描述,您几乎肯定没有任何理由使用外层循环。因此,一个好的解决方案就是将外部while改为if为此,您还需要:

  • 将其do改为then
  • 将其done改为fi

如果您选择此解决方案,那么您还需要移动当前拥有的一些命令外部(应该whileif),以便它们位于其中。现在,即使实际上不执行任何操作,也会提示用户选择一个选项。仅将 更改为whileif并进行其他两个必要的更改才能使其正常工作)无法修复该额外的错误。

另一种解决方案是让脚本在[ -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。通过更容易地识别,你还可以更好地识别何时需要关键字丢失的,通过以一致的方式缩进内容,您将能够更好地识别脚本的逻辑是否与您的意图不同。

相关内容