【问题标题】:Add (collect) exit codes in bash在 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 + $? ))

标签: bash scripting shell exit-code


【解决方案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
            猜你喜欢
            • 2013-04-27
            • 1970-01-01
            • 1970-01-01
            • 2016-08-16
            • 2023-01-26
            • 1970-01-01
            • 1970-01-01
            • 2015-05-08
            • 2020-05-19
            相关资源
            最近更新 更多