如果失败,在Bash中执行一行而不中止?

时间:2013-11-20 19:20:59

标签: bash

bash脚本中是否存在一种通用方式来“尝试”某些内容,但如果失败则会继续?其他语言中的模拟将包装在try / catch中并忽略异常。

具体来说,我正在尝试获取可选的卫星脚本文件:

. $OPTIONAL_PATH

但是在执行此操作时,如果$OPTIONAL_PATH不存在,整个脚本将停止运行。

我意识到我可以在采购之前检查文件是否存在,但我很好奇是否有一个可以使用的通用可重用机制,它会忽略错误而不会停止。

更新:显然这不是正常行为。我不确定为什么会这样。我没有明确地在任何地方调用set -e$-hB),但它会在错误上停止。这是我看到的输出:

./script.sh: line 36: projects/mobile.sh: No such file or directory

我在源代码行之后立即添加了一个echo "test",但它从不打印,所以在退出该行之后不会发生任何事情。我正在运行Mac OS 10.9。

更新2:没关系,确实是#!/bin/sh而不是#!/bin/bash。感谢您提供的信息,Kaz。

3 个答案:

答案 0 :(得分:5)

除非您使用set -e显式配置该模式,否则失败的命令不会中止脚本。

关于Bash的dot命令,事情很棘手。如果我们以/bin/sh的形式调用bash,那么如果.命令找不到该文件,则会使脚本失效。如果我们以/bin/bash调用bash,那么它不会失败!

$ cat source.sh 
#!/bin/sh

. nonexistent
echo here
$ ./source.sh 
./source.sh: 3: .: nonexistent: not found
$ ed source.sh 
35
1s/sh/bash/
wq
37
$ ./source.sh 
./source.sh: line 3: nonexistent: No such file or directory
here

它确实响应set -e;如果我们有#!/bin/bash,并使用set -e,则无法访问echo。因此,一种解决方案是以这种方式调用bash。

如果您想让脚本保持最大的可移植性,看起来您必须进行测试。

POSIX需要使用dot命令中止脚本的行为。搜索“点”关键字here。引用:

如果找不到可读文件,则非交互式shell将中止;交互式shell应将诊断消息写入标准错误,但不应将此条件视为语法错误。

可以说,这是正确的做法,因为dot用于包含脚本的各个部分。如果脚本没有被找到,那么该脚本如何继续?

否则可以说,这是与其他命令的处理不一致的braindamaged行为,因此Bash使其在非POSIX兼容模式下保持一致。如果程序员希望命令失败,他们可以使用set -e

我倾向于同意Bash。 POSIX行为实际上比最初遇到的情况更加破碎,因为这也不会按照你想要的方式工作

if . nonexistent ; then
  echo loaded
fi

即使测试了该命令,它仍会在脚本失效时中止脚本。

感谢GNU-deness,我们有其他实用程序,包含源代码。

答案 1 :(得分:2)

您有几种选择:

  1. 确保未使用set -e,或使用set +e将其关闭。默认情况下,bash脚本不会因为.命令失败而退出。

  2. 在采购之前测试该文件是否存在。

    [ -f "$OPTIONAL_PATH" ] && . "$OPTIONAL_PATH"
    

    如果$OPTIONAL_PATH不包含,则此选项很复杂 任何斜杠,.仍会尝试在您的路径中找到该文件。

  3. 如果你想保持set -e,请“隐藏”这样的失败:

    . "$OPTIONAL_PATH" || true
    

    即使源失败,由于|| true,命令列表的退出状态也将为0。

  4. (其中大部分都是由Kaz的答案覆盖[更好],特别是对POSIX标准的引用,但我不确定他何时或是否会取消他的答案。)

答案 2 :(得分:1)

这不是默认行为。您是否{1}}或在脚本中的任何位置使用set -e,以便在失败时自动退出?

如果是,您可以使用

#!/bin/bash -e

继续。