2014-04-18 54 views
1

使用trap可能有助于编写最干净的bash脚本。 不过,我想知道,以是否存在陷阱的解决方案在以下情况下的错误:Linux陷阱最佳实践&&

GNU的bash,版本4.2.45

情况确定

#!/bin/bash 
trap 'echo OK i see error at line $LINENO;exit' ERR 
unknowncommand 
echo "test KO should never reach me" 

情况下KO

#!/bin/bash 
trap 'echo OK i see error at line $LINENO;exit' ERR 
unknowncommand && echo "miss the trap" 
echo "test KO should never reach me" 
  • 不幸的是,我们到达最后一句,好像&&使整个句子不是一个ERR。
+1

http://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html如果管道[...]返回非零状态,立即退出。如果失败的命令是命令列表的一部分,紧接着关键字,if语句中的测试的一部分,在&&或||中执行的任何命令的一部分,shell不会退出。列表,除了最后的&&或||之后的命令,管道中的最后一个命令或命令的返回状态与!相反的列表。 – chris

+0

更多相关的(但基本上相同的想法)是'trap'内建文档中'ERR'伪信号的描述。 – chepner

+0

@chris令人困惑,但准确。 Bash似乎将布尔解释为命令列表,即使不使用大括号来形成列表表达式。虽然我的回答是正确的,但是你指向'-e'的指针有助于解释Bash如何解析表达式。 –

回答

5

您想要评估整个评估的退出状态,而不是尝试短路。做到这一点的一种方法是将整个事情包装在一个子外壳中。例如:

#!/bin/bash 
trap 'echo "OK i see error at line $LINENO"; exit' ERR 
(unknowncommand && echo "miss the trap") 
echo "test KO should never reach me" 

这个按预期工作。结果是这样的:

$ /tmp/err.sh 
/tmp/err.sh: line 3: unknowncommand: command not found 
OK i see error at line 3 
+0

这个(或者至少是第一部分)并不完全正确。 ERR的文档只是说如果失败的命令是列表的一部分(通过'&&'或'||'连接的命令),处理程序就不会运行。将列表包装在子外壳中会导致由于列表的非零状态而导致返回非零的子shell触发“ERR”。 – chepner

+0

@chepner我无法帮助你的shell输出“帮助陷阱”。我发布的确实是Bash 4.2.45在我的系统上打印的内容。一个假设你的里程可能会有所不同。 –

+0

这就是'trap'命令本身的返回状态,而不是'ERR'信号触发的处理程序。 'unknowncommand'仍然有一个非零的退出状态(因此subhell也是如此)。不同之处在于'ERR'处理程序没有为一个命令列表触发,但是对于一个子shell来说(显然,虽然没有在手册页中明确指出)。 – chepner

1

按照documentation for 4.2 (recent at the time of this answer)

如果SIGSPEC是ERR,只要一个简单的命令具有非零退出状态,须符合下列执行命令ARG条件。如果失败的命令是紧跟在关键字until或while后面的命令列表的一部分,则执行ERR陷阱,这是在if或elif保留字后面的测试的一部分,这是在& &或||中执行的命令的一部分。列表,或者如果命令的返回状态正在使用!反转。

之一来解决此方法是使用一个if语句来检查的$?的价值,而不是一个&&名单。

trap 'echo OK i see error at line $LINENO;exit' ERR 
unknowncommand 
if [ $? -eq 0 ]; then 
    echo "miss the trap" 
fi 
echo "test KO should never reach me" 

另外,似乎工作是在子shell来包装命令,但文档似乎没有提到ERR为一个失败的子shell解雇。 (子shell通常不被视为一个简单的命令,但文档也不会否认它。)子shell的退出状态是最后一行的退出状态,在这种情况下(x && y)是退出状态x如果失败,或者退出状态为y

trap 'echo OK i see error at line $LINENO;exit' ERR 
(unknowncommand && echo "miss the trap") 
echo "test KO should never reach me"