如何判断bash脚本中的任何命令是否失败(非零退出状态)
我想知道bash脚本中是否有任何命令以非零状态退出 我想要类似于如何判断bash脚本中的任何命令是否失败(非零退出状态),bash,sh,exit-code,exitstatus,Bash,Sh,Exit Code,Exitstatus,我想知道bash脚本中是否有任何命令以非零状态退出 我想要类似于set-e功能的东西,只是我不想在命令以非零状态退出时退出。我想让它运行整个脚本,然后我想知道: a) 退出状态为0的所有命令均已退出 -或- b) 一个或多个命令以非零状态退出 e、 g.鉴于以下情况: #!/bin/bash command1 # exits with status 1 command2 # exits with status 0 command3 # exits with status 0 我希望这
set-e
功能的东西,只是我不想在命令以非零状态退出时退出。我想让它运行整个脚本,然后我想知道:
a) 退出状态为0的所有命令均已退出-或-
b) 一个或多个命令以非零状态退出
e、 g.鉴于以下情况:
#!/bin/bash
command1 # exits with status 1
command2 # exits with status 0
command3 # exits with status 0
我希望这三个命令都能运行。运行脚本后,我希望指示至少一个命令以非零状态退出。bash中提供了魔法变量
$?
,该变量告诉最后一个命令的退出代码:
#!/bin/bash
command1 # exits with status 1
C1_output=$? # will be 1
command2 # exits with status 0
C2_output=$? # will be 0
command3 # exits with status 0
C3_output=$? # will be 0
我不确定是否有现成的解决方案满足您的要求。我将编写如下函数:
function run_cmd_with_check() {
"$@"
[[ $? -ne 0 ]] && ((non_zero++))
}
然后,使用该函数运行所有需要跟踪的命令:
run_cmd_with_check command1
run_cmd_with_check command2
run_cmd_with_check command3
printf "$non_zero commands exited with non-zero exit code\n"
如果需要,可以增强该功能,将所有失败的命令存储在一个数组中,并在最后打印出来
您可能想查看这篇文章以了解更多信息:对于可以执行此操作的每个命令:
if ! Command1 ; then an_error=1; fi
并对所有命令重复此操作
最后,如果其中任何一个失败,则_错误将为1
如果需要失败计数,请在开始时将_错误设置为0,然后执行$(_错误++)。您可以将命令列表放入数组中,然后在命令上循环,而不是_error=1。任何返回错误代码的操作都会保留结果以供以后查看
declare -A results
commands=("your" "commands")
for cmd in "${commands[@]}"; do
out=$($cmd 2>&1)
[[ $? -eq 0 ]] || results[$cmd]="$out"
done
然后查看任何非零退出代码:
for cmd in "${!results[@]}"; do echo "$cmd = ${results[$cmd]}"; done
如果results
的长度为0,则命令列表中没有错误
这需要bash4+(对于关联数组)您可以尝试使用
调试
伪信号的陷阱,例如
trap '(( $? && ++errcount ))' DEBUG
执行调试
陷阱
在每个简单命令之前,for
命令、case
命令、select
命令、每个算术for
命令,以及在shell函数中执行第一个命令之前
(引自)
因此,如果您添加此陷阱,并且作为最后一个打印错误计数的命令,您将获得正确的值:
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
echo "Errors: $errcount"
返回错误:1
和
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
false
echo "Errors: $errcount"
打印
错误:2
。请注意,最后一条语句实际上需要解释第二个false
,因为陷阱是在命令之前执行的,所以只有在执行echo
行的陷阱时,才会检查第二个false
的退出状态。您可以使用调试陷阱,如:
trap 'code+=$?' DEBUG
code=0
# run commands here normally
exit $code
在错误上设置陷阱:
#!/bin/bash
err=0
trap 'err=1' ERR
command1
command2
command3
test $err = 0 # Return non-zero if any command failed
您甚至可以进行一些自省,以获取有关错误发生位置的数据:
#!/bin/bash
for i in 1 2 3; do
eval "command$i() { echo command$i; test $i != 2; }"
done
err=0
report() {
err=1
echo -n "error at line ${BASH_LINENO[0]}, in call to "
sed -n ${BASH_LINENO[0]}p $0
} >&2
trap report ERR
command1
command2
command3
exit $err
是的,我知道。这并不能直接回答我的问题。您可能暗示我可以修改脚本以保持所有退出状态的运行总数。这将是一个解决方案,但不是一个理想的解决方案,因为它需要在一个包含30条命令的脚本中添加30行代码,这使得它更难阅读,并且容易由于忘记将其添加到每个命令而导致人为错误。我认为可以创建一个函数,并将每个命令传递给该函数。还是挺麻烦的。我希望有一个简单的set-e
类型的解决方案。@RobBednark这可能是你能做的最好的了。考虑一个命令,如<代码>((x=0))< /代码>。从技术上讲,这是一个失败的命令,因为包含的表达式的计算结果为0。任何自动化的东西都必须考虑到这一点。set-e
的问题在于失败的命令不一定是错误。@GrishaLevit-你说得对-我更正了答案。看起来引用的主题总是让人困惑…完美,正是我想要的!谢谢@William_Pursell!