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。
答案 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)
您有几种选择:
确保未使用set -e
,或使用set +e
将其关闭。默认情况下,bash
脚本不会因为.
命令失败而退出。
在采购之前测试该文件是否存在。
[ -f "$OPTIONAL_PATH" ] && . "$OPTIONAL_PATH"
如果$OPTIONAL_PATH
不包含,则此选项很复杂
任何斜杠,.
仍会尝试在您的路径中找到该文件。
如果你想保持set -e
,请“隐藏”这样的失败:
. "$OPTIONAL_PATH" || true
即使源失败,由于|| true
,命令列表的退出状态也将为0。
(其中大部分都是由Kaz的答案覆盖[更好],特别是对POSIX标准的引用,但我不确定他何时或是否会取消他的答案。)
答案 2 :(得分:1)
这不是默认行为。您是否{1}}或在脚本中的任何位置使用set -e
,以便在失败时自动退出?
如果是,您可以使用
#!/bin/bash -e
继续。