抱歉,我无法给出明确的标题,但这里是简化的问题代码。
#!/bin/bash
# get the absolute path of .conf directory
get_conf_dir() {
local path=$(some_command) || { echo "please install some_command first."; exit 100; }
echo "$path"
}
# process the configuration
read_conf() {
local conf_path="$(get_conf_dir)/foo.conf"
[ -r "$conf_path" ] || { echo "conf file not found"; exit 200; }
# more code ...
}
read_conf
因此,基本上我想做的是在bash脚本中读取一个简单的配置文件,并且在错误处理方面遇到了一些麻烦。
some_command 是来自第三方库(即coreutils中的greadlink)的命令,该命令是获取路径所必需的。
当运行上面的代码时,我希望它输出“找不到命令”,因为这是发生FIRST错误的地方,但实际上它总是打印“找不到conf文件”。
我对这种行为感到非常困惑,我认为BASH可能打算处理这样的事情,但我不知道为什么。最重要的是,如何解决?
任何想法将不胜感激。
最佳答案
您在任何地方都可以看到please install some_command first
消息吗?它是$conf_path
行中的local conf_path="$(get_conf_dir)/foo.conf"
吗?您的$conf_path
值是否为please install some_command first/foo.conf
?哪一个未通过-r
测试?
不,你没有。 (但是请随时在该$conf_path
块中回显exit 200
的值以确认这一事实。)(此外,一般来说,错误消息应该发送到标准错误而不是标准输出。因此,它们应该是echo "..." 2>&1
。完全不会被普通的命令替换所捕获。)
您之所以不这样做,是因为exit 100
块是,从来没有发生过。
您也可以在脚本顶部使用set -x
看到它。去试试看。
明白了吗?
之所以没有发生,是因为some_command
赋值语句吞噬了local path=$(some_command)
的失败返回。
尝试运行以下命令:
f() { local a=$(false); echo "Returned: $?"; }; f
您希望看到
Returned: 1
吗?您可能会看到,但看不到。您将看到的是
Returned: 0
。现在尝试以下任一版本:
f() { a=$(false); echo "Returned: $?"; }; f
f() { local a; a=$(false); echo "Returned: $?"; }; f
首先获得您期望的输出?
对。
local
和export
以及declare
和typeset
是自己的语句。它们有自己的返回值。他们忽略(并替换)在其上下文中执行的命令的返回值。您的问题的解决方案是拆分
local path
和path=$(some_command)
语句。http://www.shellcheck.net/捕获了此错误(以及许多其他常见错误)。你应该让它成为你的 friend 。
除了上述内容(如果您到目前为止已经设法完成)以外,即使到目前为止已提及更改,您的
exit 100
也不会退出主脚本,因为它只会退出由任务替换中的命令替换产生的子 shell 。如果您想让
exit 100
退出脚本,则您需要注意并重新退出脚本(在get_conf_dir
分配后检查conf_path
是否失败,并使用先前的退出代码退出),或者删除get_conf_dir
函数本身,然后直接内联read_conf
。
关于bash - 使用$(func)调用有问题的函数时,Bash脚本不会在第一次 “exit”调用时退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31522274/