通过管道进入while循环获取流程替换的退出代码 [英] Get exit code of process substitution with pipe into while loop
问题描述
The following script calls another program reading its output in a while loop (see Bash - How to pipe input to while loop and preserve variables after loop ends):
while read -r col0 col1; do
# [...]
done < <(other_program [args ...])
如何检查other_program
的退出代码以查看循环是否正确执行?
How can I check for the exit code of other_program
to see if the loop was executed properly?
推荐答案
注意:ls -d / /nosuch
在下面用作示例命令,因为它仍然失败(退出代码1
),同时仍生成标准输出(</
)(除了stderr输出).
Note: ls -d / /nosuch
is used as an example command below, because it fails (exit code 1
) while still producing stdout output (/
) (in addition to stderr output).
ccarton的有用答案原则上效果很好,但是默认情况下,while
循环在子外壳中运行,这意味着在循环中创建或修改的任何变量对 current 外壳都是不可见的.
ccarton's helpful answer works well in principle, but by default the while
loop runs in a subshell, which means that any variables created or modified in the loop will not be visible to the current shell.
在 Bash v4.2 + 中,您可以通过打开 lastpipe
选项来更改此设置,这将使 last 部分成为在 current 外壳中运行的管道;
就像在ccarton的答案中一样,必须将 pipefail
选项设置为使$?
反映管道中第一个 failing 命令的退出代码:
In Bash v4.2+, you can change this by turning the lastpipe
option on, which makes the last segment of a pipeline run in the current shell;
as in ccarton's answer, the pipefail
option must be set to have $?
reflect the exit code of the first failing command in the pipeline:
shopt -s lastpipe # run the last segment of a pipeline in the current shell
shopt -so pipefail # reflect a pipeline's first failing command's exit code in $?
ls -d / /nosuch | while read -r line; do
result=$line
done
echo "result: [$result]; exit code: $?"
以上结果(省略了stderr输出):
The above yields (stderr output omitted):
result: [/]; exit code: 1
如您所见,在while
循环中设置的$result
变量可用,并且ls
命令的(非零)退出代码反映在$?
中.
As you can see, the $result
variable, set in the while
loop, is available, and the ls
command's (nonzero) exit code is reflected in $?
.
ikkachu的有用答案效果很好,并且显示了先进的技术,但这有点麻烦.
这是一个更简单的选择:
ikkachu's helpful answer works well and shows advanced techniques, but it is a bit cumbersome.
Here is a simpler alternative:
while read -r line || { ec=$line && break; }; do # Note the `|| { ...; }` part.
result=$line
done < <(ls -d / /nosuch; printf $?) # Note the `; printf $?` part.
echo "result: [$result]; exit code: $ec"
-
通过将
ls
命令的退出代码$?
的值附加到输出而没有尾随的\n
(printf $?
),read
读取它在最后一次循环操作中,但指示失败(退出代码1),通常会退出循环.By appending the value of
$?
, thels
command's exit code, to the output without a trailing\n
(printf $?
),read
reads it in the last loop operation, but indicates failure (exit code 1), which would normally exit the loop.我们可以使用
||
检测到这种情况,然后将退出代码(仍被读入$line
的代码)分配给变量$ec
,然后退出循环.We can detect this case with
||
, and assign the exit code (that was still read into$line
) to variable$ec
and exit the loop then.在命令输出没有尾随
\n
的偶然机会上,需要做更多的工作:On the off chance that the command's output doesn't have a trailing
\n
, more work is needed:while read -r line || { [[ $line =~ ^(.*)/([0-9]+)$ ]] && ec=${BASH_REMATCH[2]} && line=${BASH_REMATCH[1]}; [[ -n $line ]]; } do result=$line done < <(printf 'no trailing newline'; ls /nosuch; printf "/$?") echo "result: [$result]; exit code: $ec"
以上结果(省略了stderr输出):
The above yields (stderr output omitted):
result: [no trailing newline]; exit code: 1
这篇关于通过管道进入while循环获取流程替换的退出代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!