忽略 Bash 中的特定退出代码

epl*_*epl 9 unix linux bash scripting

注意:问题不会重复Ignoring certain Errors in a shell script


假设需要捕获文件的编码表示形式的前导字符。

在 shell 中(在 Bash 中测试),很容易使用以下形式:

encoded="$(< file base64 | head -c16)"
Run Code Online (Sandbox Code Playgroud)

除非环境发生某些改变,否则该语句将发挥所需的作用。

考虑以下:

set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$(< file base64 | head -c16)"
Run Code Online (Sandbox Code Playgroud)

最后一行将导致脚本终止,因为 给出的非零返回状态 (141)base64对关闭的管道不满意。返回状态被传播到管道,然后传播到调用 shell。

不良效果需要解决方法,如下所示:

set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< file base64 || :) | head -c16)"
Run Code Online (Sandbox Code Playgroud)

:与关键字 , 具有相同的效果,true评估为非错误。

然而,这种方法会导致进一步的不良影响。

下面显示了具有不同错误的变体:

set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< /not/a/real/file base64 || :) | head -c16)"
echo $?
Run Code Online (Sandbox Code Playgroud)

打印的代码为零。现在,一个真正的错误已被掩盖。

最明显的解决方案如下,相当冗长

set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< /not/a/real/file base64 || [ $? == 141 ]) | head -c16)"
echo $?
Run Code Online (Sandbox Code Playgroud)

有更紧凑的形式吗?是否可以进行任何环境更改,以便语句仅屏蔽特定的状态代码,而无需显式内联表达式?

mas*_*ilo 1

首先,显然,要真正引发 141 错误,文件需要相当大,例如

head -c 1000000 /dev/urandom > file
Run Code Online (Sandbox Code Playgroud)

现在,正如您所说,该脚本sh.sh将在显示之前终止encoded: ...

head -c 1000000 /dev/urandom > file
Run Code Online (Sandbox Code Playgroud)

您可以通过在完成后调用base64继续将其其余数据传输到管道,而不是检查错误代码:/dev/nullcat > /dev/nullhead

#!/bin/bash
set -o errexit -o pipefail
shopt -s inherit_errexit

encoded="$(< file base64 | head -c16)"

echo "encoded: $encoded"
Run Code Online (Sandbox Code Playgroud)

现在你会得到encoded: NvyX2Zx4nTDjtQO8什么。

这不会掩盖其他错误,例如文件不存在:

$ ./sh.sh
./sh.sh: line 5: file: No such file or directory

Run Code Online (Sandbox Code Playgroud)

但是,效率会较低,因为将读取整个文件。