如何判断 bash 脚本中的任何命令是否失败(非零退出状态)
How to tell if any command in bash script failed (non-zero exit status)
我想知道 bash 脚本中是否有任何命令以非零状态退出。
我想要类似于 set -e
功能的东西,只是我不希望它在命令以非零状态退出时退出。我想要 运行 整个脚本,然后我想知道:
a) 所有命令以退出状态 0 退出
- 或 -
b) 一个或多个命令以非零状态退出
例如,给定以下内容:
#!/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
我不确定是否有满足您要求的 ready-made 解决方案。我会写一个这样的函数:
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"
如果需要,可以增强该功能,将所有失败的命令存储在一个数组中,最后打印出来。
您可能想看看这个 post 以获取更多信息:Error handling in Bash
对于每个命令,您可以这样做:
if ! Command1 ; then an_error=1; fi
并对所有命令重复此操作
最后 an_error 如果其中任何一个失败,则为 1。
如果你想计算失败次数,请在开始时将 an_error 设置为 0,然后执行 $((an_error++))。而不是 an_error=1
您可以将命令列表放入一个数组中,然后循环执行这些命令。任何 return 错误代码都可以保留结果供以后查看。
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,则您的命令列表中没有错误。
这需要 Bash 4+(对于关联数组)
您可以尝试对 DEBUG
伪信号做一些陷阱,例如
trap '(( $? && ++errcount ))' DEBUG
执行DEBUG
陷阱
before every simple command, for
command, case
command, select
command, every arithmetic for
command, and before the first command executes in a shell function
(引自 manual)。
因此,如果您添加此陷阱并将其作为打印错误计数的最后命令,您将获得正确的值:
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
echo "Errors: $errcount"
returns Errors: 1
和
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
false
echo "Errors: $errcount"
打印 Errors: 2
。请注意,实际上需要最后一条语句来说明第二个 false
,因为陷阱是在 命令之前 执行的,因此第二个 false
的退出状态是仅在执行 echo
行的陷阱时检查。
您可以像这样使用 DEBUG
陷阱:
trap 'code+=$?' DEBUG
code=0
# run commands here normally
exit $code
在 ERR 上设置陷阱:
#!/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 [=11=]
} >&2
trap report ERR
command1
command2
command3
exit $err
我想知道 bash 脚本中是否有任何命令以非零状态退出。
我想要类似于 set -e
功能的东西,只是我不希望它在命令以非零状态退出时退出。我想要 运行 整个脚本,然后我想知道:
a) 所有命令以退出状态 0 退出
- 或 -
b) 一个或多个命令以非零状态退出
例如,给定以下内容:
#!/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
我不确定是否有满足您要求的 ready-made 解决方案。我会写一个这样的函数:
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"
如果需要,可以增强该功能,将所有失败的命令存储在一个数组中,最后打印出来。
您可能想看看这个 post 以获取更多信息:Error handling in Bash
对于每个命令,您可以这样做:
if ! Command1 ; then an_error=1; fi
并对所有命令重复此操作
最后 an_error 如果其中任何一个失败,则为 1。
如果你想计算失败次数,请在开始时将 an_error 设置为 0,然后执行 $((an_error++))。而不是 an_error=1
您可以将命令列表放入一个数组中,然后循环执行这些命令。任何 return 错误代码都可以保留结果供以后查看。
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,则您的命令列表中没有错误。
这需要 Bash 4+(对于关联数组)
您可以尝试对 DEBUG
伪信号做一些陷阱,例如
trap '(( $? && ++errcount ))' DEBUG
执行DEBUG
陷阱
before every simple command,
for
command,case
command,select
command, every arithmeticfor
command, and before the first command executes in a shell function
(引自 manual)。
因此,如果您添加此陷阱并将其作为打印错误计数的最后命令,您将获得正确的值:
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
echo "Errors: $errcount"
returns Errors: 1
和
#!/usr/bin/env bash
trap '(( $? && ++errcount ))' DEBUG
true
false
true
false
echo "Errors: $errcount"
打印 Errors: 2
。请注意,实际上需要最后一条语句来说明第二个 false
,因为陷阱是在 命令之前 执行的,因此第二个 false
的退出状态是仅在执行 echo
行的陷阱时检查。
您可以像这样使用 DEBUG
陷阱:
trap 'code+=$?' DEBUG
code=0
# run commands here normally
exit $code
在 ERR 上设置陷阱:
#!/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 [=11=]
} >&2
trap report ERR
command1
command2
command3
exit $err