2015-07-20 53 views
1

对不起,我不能给出明确的标题,但这里是简化的问题代码。

#!/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)获取路径所需的命令。

当运行上面的代码时,我期望它输出“command not found”,因为这是FIRST错误发生的地方,但实际上它总是打印“找不到conf文件”。

我对这样的行为非常困惑,我认为BASH可能意图处理这样的事情,但我不知道为什么。而最重要的是,如何解决它?

任何想法将不胜感激。

回答

2

您是否在任何地方看到过您的please install some_command first消息?从local conf_path="$(get_conf_dir)/foo.conf"行是$conf_path?你有$conf_pathplease install some_command first/foo.conf?那么-r测试失败了?不,你不这样做。 (但是请随意在exit 200块中回显$conf_path的值以确认这一事实)。(另外,错误消息一般应发送到标准错误而不是标准输出,因此它们应该是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 

让你在第一位置预期的输出?

对。 localexportdeclaretypeset是他们自己的声明。他们有自己的回报价值。他们忽略(并替换)在其上下文中执行的命令的返回值。

解决您的问题的方法是拆分local pathpath=$(some_command)语句。

http://www.shellcheck.net/捕获此(和许多其他常见错误)。你应该让它成为你的朋友。

除了上述(如果你已经设法跟上这一点),即使到目前为止提到的更改,您的exit 100不会退出主脚本,因为它只会退出由命令产生的子shell替代任务。

如果希望exit 100退出脚本,那么你要么需要注意并重新退出与它(检查是否有conf_path分配和退出与前退出代码后get_conf_dir衰竭)或掉落get_conf_dir功能本身,只是请在read_conf内联。

+1

也许值得更加明确的消息'请先安装some_command'发送到stdout而不是stderr。以及'get_conf_dir'中的'exit'只能从'$(get_conf_dir)'中的子shell中退出。 – rici

+0

@rici绝对正确。我在那里失去了树林。更新。 –

+0

@林我解决了你的一些问题。并且让你能够正确处理你的'出口100'故障,因为它真的发生了。但是,正如rici指出的那样,你不能在那里退出100退出脚本。它在一个子shell中。查看最新答案中的最后一段。 –