在 bash 中添加(收集)退出代码

Posted

技术标签:

【中文标题】在 bash 中添加(收集)退出代码【英文标题】:Add (collect) exit codes in bash 【发布时间】:2009-06-16 09:14:28 【问题描述】:

我需要依赖脚本中的几个单独执行,并且不想将它们全部捆绑在一个丑陋的“if”语句中。我想使用退出代码“$?”每次执行并添加它;最后,如果这个值超过阈值 - 我想执行一个命令。

伪代码:

ALLOWEDERROR=5

run_something
RESULT=$?
..other things..

run_something_else
RESULT=$RESULT + $?

if [ $RESULT -gt ALLOWEDERROR ] 
   then echo "Too many errors"
fi

问题:尽管 Internet 声称并非如此,bash 拒绝处理 RESULT 和 $?作为整数。正确的语法是什么?

谢谢。

【问题讨论】:

result=$(( result + $? )) 【参考方案1】:

您可能想看看 trap 内置函数,看看它是否有用:

help trap

man bash

您可以为这样的错误设置陷阱:

#!/bin/bash

AllowedError=5

SomeErrorHandler () 
    (( errcount++ ))       # or (( errcount += $? ))
    if  (( errcount > $AllowedError ))
    then
        echo "Too many errors"
        exit $errcount
    fi


trap SomeErrorHandler ERR

for i in 1..6
do
    false
    echo "Reached $i"     # "Reached 6" is never printed
done

echo "completed"          # this is never printed

如果您像这样计算错误(并且仅当它们是错误时)而不是使用“$?”,那么您不必担心返回值不是零或一。例如,单个返回值 127 会立即使您超过阈值。除了ERR之外,您还可以注册traps 用于其他信号。

【讨论】:

【参考方案2】:

快速实验并深入了解 bash 信息说:

declare -i RESULT=$RESULT + $?

由于您多次添加到结果中,您可以在开始时使用声明,如下所示:

declare -i RESULT=0

true
RESULT+=$?
false
RESULT+=$?
false
RESULT+=$?

echo $RESULT
2

看起来干净多了。

declare -i 表示变量是整数。

您也可以避免声明和使用算术表达式括号:

RESULT=$(($RESULT+$?))

【讨论】:

最后一个只计算执行次数,不考虑错误(或成功):RESULT=$(($RESULT+1))。如果要使用 $(()) 构造,则需要添加 $?而不是 1(如 Dave Hinton 的回答)。否则,即使命令返回 0,您也会递增。或者您可以使用我的答案中的陷阱。 谢谢您,我已在您的修复中进行了编辑。我喜欢你的回答。 如果一行的返回码为 -1 而另一行的返回码为 1,这将不起作用,因为它们加起来看起来像成功(即 0)。跨度> 【参考方案3】:

使用$(( ... )) 构造。

$ cat st.sh
RESULT=0
true
RESULT=$(($RESULT + $?))
false
RESULT=$(($RESULT + $?))
false
RESULT=$(($RESULT + $?))
echo $RESULT
$ sh st.sh
2
$

【讨论】:

【参考方案4】:

有关如何在 Bash 中添加数字,另请参阅:

help let 

【讨论】:

【参考方案5】:

如果您想在脚本中使用 ALLOWEDERROR,请在其前面加上 $,例如 $ALLOWEDERROR。

【讨论】:

【参考方案6】:

正如 mouviciel 提到的那样,收集返回码的总和看起来相当无意义。可能,您可以使用数组来累积非零结果代码并检查其长度。这种方法的例子如下:

#!/bin/sh

declare RESULT
declare index=0
declare ALLOWED_ERROR=1

function write_result 
    if [ $1 -gt 0 ]; then
        RESULT[index++]=$1
    fi


true
write_result $?

false
write_result $?

false
write_result $?

echo $#RESULT[*]
if [ $#RESULT[*] -gt $ALLOWEDERROR ] 
   then echo "Too many errors"
fi

【讨论】:

【参考方案7】:

以下是一些在 bash 或 sh 中执行加法的方法:

RESULT=`expr $RESULT + $?`
RESULT=`dc -e "$RESULT $? + pq"`

还有一些仅在 bash 中的:

RESULT=$((RESULT + $?))
RESULT=`bc <<< "$RESULT + $?"` 

无论如何,错误退出状态并不总是 1,其值也不取决于错误级别,因此在一般情况下,根据阈值检查状态总和没有多大意义。

【讨论】:

我会为你答案的“不总是 1”部分给你一个 +1,但我不会因为 a) 你使用反引号而不是 $() 和 b) expr 是在 bash 和 3) 中是不必要的,并且 dc 对添加来说太过分了。如果 OP 使用 sh 而不是 bash(或者如果它是为了可移植性),那么 expr 和 back tick 就可以了。 ...和 ​​d) 为什么没有 RESULT=bc &lt;&lt;&lt; "$RESULT + $?" 没有理由在任何符合 POSIX sh 规范的原始 1991 版本的 shell 中使用 expr$(( ... )) 已经提供了更快、更高效的内置语法,现在不需要分叉子进程和 exec()'ing 外部命令 decades ...也就是说,$(( ... )) 绝对不是 bash-only;它适用于每个符合标准的/bin/sh

以上是关于在 bash 中添加(收集)退出代码的主要内容,如果未能解决你的问题,请参考以下文章

在 Bash 脚本中获取 Python 脚本的退出代码

为啥在 ERR 陷阱中退出 0 时 bash 会抑制标准输出?

在 Bash 和 KornShell (ksh) 中获取命令的退出代码

Bash:如何在使用微调器时获取命令的退出代码?

在 bash 中退出并显示错误消息(单行)

在 Bash 脚本中,如果发生某种情况,如何退出整个脚本?