15

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

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

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


例如,给定以下内容:

#!/bin/bash

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

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

4

7 回答 7

9

在 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
于 2017-02-14T06:57:06.470 回答
4

您可以尝试对伪信号进行陷阱处理DEBUG,例如

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

DEBUG陷阱被执行

在每个简单命令、for命令、case命令、select命令、每个算术for命令之前,以及在 shell 函数中执行第一个命令之前

(引自手册)。

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

#!/usr/bin/env bash

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

true
false
true

echo "Errors: $errcount"

返回Errors: 1

#!/usr/bin/env bash

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

true
false
true
false

echo "Errors: $errcount"

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

于 2017-02-14T06:09:14.327 回答
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"

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


您可能想查看这篇文章以获取更多信息:Bash 中的错误处理

于 2017-02-14T04:59:33.730 回答
0

您可以DEBUG像这样使用陷阱:

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

# run commands here normally

exit $code
于 2017-02-14T06:09:21.370 回答
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+(用于关联数组)

于 2017-02-14T05:39:56.307 回答
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
于 2017-02-14T04:45:21.903 回答
0

对于每个命令,您可以这样做:

if ! Command1 ; then an_error=1; fi 

并对所有命令重复此操作

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

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

于 2017-02-14T05:01:42.860 回答