pef*_*cio 2 bash bash-scripting
我正在玩 Bash 脚本。我想将命令的结果分配给一个变量,并将其返回代码分配给另一个变量。
前任。:
line_count=$(cat "$filename" | wc -l) #If the file does not exist, an error code is returned
cmd_return_code=$? #I want to assign the previous error code to a variable
Run Code Online (Sandbox Code Playgroud)
我尝试如上所示使用$?,但它捕获了前一个赋值本身的返回码,即 0。
我怎样才能做到这一点?
谢谢
这里的问题是,在管道中cat "$filename" | wc -l,当文件不存在时,cat会出现错误退出,但wc -l会成功计算从 接收到的 0 行文本cat。管道中最后一个命令的退出状态被视为整个管道的最终状态,因此整个管道被认为是成功的。像这样:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "$?"
0
Run Code Online (Sandbox Code Playgroud)
通常在 bash 中,您可以使用数组获取管道中单个命令的状态PIPESTATUS,如下所示:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "${PIPESTATUS[@]}"
1 0
Run Code Online (Sandbox Code Playgroud)
...但这不适用于命令扩展中的管道$( ),因为该管道将在子 shell 中执行,并且PIPESTATUS无法从子 shell 传播;只有最终状态会传递回父 shell:
$ line_count=$(cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "${PIPESTATUS[@]}"
0
Run Code Online (Sandbox Code Playgroud)
那么,你能对此做些什么呢?好吧,正如 l0b0 所说,一种可能性是设置选项pipefail。您不必对整个脚本执行此操作,您可以通过在命令替换中执行此操作来仅针对特定子 shell 进行设置:
$ line_count=$(set -o pipefail; cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "$?"
1
Run Code Online (Sandbox Code Playgroud)
对于这个特定的命令,您还可以消除管道(这就是所谓的cat 的无用使用,或 UUOC),并wc通过将文件名作为参数传递来直接从文件中读取:
$ line_count=$(wc -l nosuchfile)
wc: nosuchfile: open: No such file or directory
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)
...或者通过使用输入重定向:
$ line_count=$(wc -l <nosuchfile)
-bash: nosuchfile: No such file or directory
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)
这两个选项之间有一些区别:如果您将文件名传递给wc(并且它存在),它将输出文件名以及行数:
$ line_count=$(wc -l realfile.txt)
$ echo "$line_count"
6 realfile.txt
Run Code Online (Sandbox Code Playgroud)
...而使用重定向选项则不会。另外,使用第二个选项时,shell 负责打开文件(并将打开的文件句柄交给命令wc),因此如果失败,shell 会给出错误(请注意,错误消息来自“-bash”,不wc)并且wc永远不会运行。
| 归档时间: |
|
| 查看次数: |
2420 次 |
| 最近记录: |