如何判断bash脚本中的任何命令是否失败(非零退出状态)

时间:2017-02-14 04:42:59

标签: bash sh exit-code exitstatus

我想知道bash脚本中的任何命令是否以非零状态退出。

我想要类似于set -e功能的东西,除了当命令以非零状态退出时我不希望它退出。我想让它运行整个脚本,然后我想知道:

a)退出状态为0的所有命令退出 - 或 -
b)一个或多个以非零状态退出的命令


例如,给出以下内容:

#!/bin/bash

command1  # exits with status 1
command2  # exits with status 0
command3  # exits with status 0

我希望所有三个命令都能运行。运行脚本后,我想要一个指示,即至少有一个命令以非零状态退出。

7 个答案:

答案 0 :(得分:7)

在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 $0
} >&2
trap report ERR

command1
command2
command3
exit $err

答案 1 :(得分:3)

您可以尝试使用DEBUG伪信号的陷阱执行某些操作,例如

trap '(( $? && ++errcount ))' DEBUG

在每个简单命令,DEBUG命令,for命令,case命令,每个算术select命令之前执行for陷阱第一个命令在shell函数中执行“(引自手册)。

因此,如果您添加此陷阱并作为最后一个命令来打印错误计数,您将获得正确的值:

#!/bin/bash

trap '(( $? && ++errcount ))' DEBUG

true
false
true

echo "Errors: $errcount"

返回Errors: 1

#!/bin/bash

trap '(( $? && ++errcount ))' DEBUG

true
false
true
false

echo "Errors: $errcount"

打印Errors: 2。请注意,最后一个语句实际上需要考虑第二个false,因为在命令之前执行了陷阱,因此仅检查第二个false的退出状态。执行echo行的陷阱。

答案 2 :(得分:1)

我不确定是否有针对您的要求的现成解决方案。我会写一个这样的函数:

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"

如果需要,可以增强该功能,将所有失败的命令存储在一个阵列中,最后可以打印出来。

您可能需要查看此帖子以获取更多信息:Error handling in Bash

答案 3 :(得分: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

答案 4 :(得分:0)

对于每个命令,您可以执行此操作:

if ! Command1 ; then an_error=1; fi 

对所有命令重复此操作

如果其中任何一个失败,an_error将为1。

如果你想要计算失败次数,那么在开始时将an_error设置为0并执行$((an_error ++))。而不是an_error = 1

答案 5 :(得分:0)

您可以将命令列表放入数组中,然后循环执行命令。任何返回错误代码的都会保留结果供以后查看。

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+(用于关联数组)

答案 6 :(得分:0)

您可以使用DEBUG陷阱,如:

trap 'code+=$?' DEBUG
code=0

# run commands here normally

exit $code