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)
有更紧凑的形式吗?是否可以进行任何环境更改,以便语句仅屏蔽特定的状态代码,而无需显式内联表达式?
首先,显然,要真正引发 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)
但是,效率会较低,因为将读取整个文件。