设置errexit选项时检测shell退出代码的正确方法

Dan*_*Lin 42 shell

我更喜欢编写可靠的shell代码,因此总是设置errexit和nounset.

以下代码将在bad_command行停止

#!/bin/bash
set -o errexit ; set -o nounset
bad_command # stop here
good_command
Run Code Online (Sandbox Code Playgroud)

我想抓住它,这是我的方法

#!/bin/bash
set -o errexit ; set -o nounset
rc=1
bad_command && rc=0 # stop here
[ $rc -ne 0 ] && do_err_handle
good_command
Run Code Online (Sandbox Code Playgroud)

有没有更好或更清洁的方法

我的答案:

#!/bin/bash
set -o errexit ; set -o nounset
if ! bad_command ; then
  # error handle here
fi
good_command
Run Code Online (Sandbox Code Playgroud)

rra*_*nza 42

这个怎么样?如果你想要实际的退出代码......

#!/bin/sh                                                                       
set -e

cat /tmp/doesnotexist && rc=$? || rc=$?                                         
echo exitcode: $rc        

cat /dev/null && rc=$? || rc=$?                                                 
echo exitcode: $rc   
Run Code Online (Sandbox Code Playgroud)

输出:

cat: /tmp/doesnotexist: No such file or directory
exitcode: 1
exitcode: 0
Run Code Online (Sandbox Code Playgroud)

  • 我发现在同一行中使用“&&”和“||”有点不直观。另一种方法是首先定义 `rc=0` 并仅在命令失败时将 `rc` 设置为实际退出代码: `rc=0; 猫 /tmp/doesnotexist || rc=$?`. 这是有效的,因为 `&&` 之后的代码段总是将 `rc` 设置为零,因此您也可以修改自己的代码以表示 `... && rc=0 || ...` (3认同)
  • 我喜欢这种方法,它很瘦. (2认同)
  • @MichelMüller它可以工作,因为整个语句一起工作,最后的错误代码是0,所以errexit不会退出.是的,你的解释,括号,似乎是正确的.事实上,你可以测试一下:试试这个````ls fakefile && x = 1 || x = 2; echo $ x``` (2认同)

小智 18

继续使用errexit.它可以帮助查找可能具有不可预测(并且难以检测)结果的错误.

#!/bin/bash
set -o errexit ; set -o nounset

bad_command || do_err_handle
good_command
Run Code Online (Sandbox Code Playgroud)

以上工作正常.errexit只需要线路通过,就像你做的那样bad_command && rc=0.因此,上面带有'或'只会在bad_command失败的情况下运行do_err_handle ,并且只要do_err_handle也不会'失败',那么脚本将继续.

  • 这是正确的做法.要进一步扩展,bad_command || {echo"我的错误信息解释了崩溃的原因"; 退出1} (4认同)

yar*_*lig 7

继续编写可靠的 shell 代码。

如果 bad_command 确实是一个命令,那么你就做对了。但要小心 if、while、||、&& 或 ! 中的函数调用,因为 errexit 在那里不起作用。这可能很危险。

如果你的 bad_command 实际上是 bad_function 你应该这样写:

set -eu 

get_exit_code() {
    set +e
    ( set -e;
      "$@"
    )
    exit_code=$?
    set -e
}

...

get_exit_code bad_function

if [ "$exit_code" != 0 ]; then
    do_err_handle
fi
Run Code Online (Sandbox Code Playgroud)

这在 bash 4.0 中运行良好。在 bash 4.2 中,您只能获得退出代码 0 或 1。

更新:bash 5.0 中的退出代码没有问题。


jos*_*sch 7

@rrauenza 给出的答案略有不同。由于&& rc=$?部分是他们的答案将始终等于&& rc=01 也可以在运行命令之前设置rc0。在我看来,结果最终更具可读性,因为变量是在它自己的代码行中预先定义的,并且只有在命令以非零退出状态退出时才会更改。如果nounset也给出了,那么现在很明显,rc确实从未未定义。这也避免了混合&&||在同一行中,这可能会令人困惑,因为人们可能并不总是牢记运算符的优先级。

#!/bin/sh                                                                       
set -eu

rc=0
cat /tmp/doesnotexist || rc=$?                                         
echo exitcode: $rc        

rc=0
cat /dev/null || rc=$?                                                 
echo exitcode: $rc   
Run Code Online (Sandbox Code Playgroud)

输出:

cat: /tmp/doesnotexist: No such file or directory
exitcode: 1
exitcode: 0
Run Code Online (Sandbox Code Playgroud)


小智 6

设置错误退出

错误命令 || {
  响应代码=$?
  echo $resp_code 发生了坏事
}