[英]Get exit code of process substitution with pipe into while loop
以下脚本调用另一个程序在while循环中读取其输出(请参阅Bash - 如何将输入传递给while循环并在循环结束后保留变量 ):
while read -r col0 col1; do
# [...]
done < <(other_program [args ...])
如何查看other_program
的退出代码以查看循环是否正确执行?
至少有一种方法是通过命名管道重定向后台进程的输出。 这将允许获取其PID,然后通过wait
PID获得退出状态。
#!/bin/bash
mkfifo pipe || exit 1
(echo foo ; exit 19) > pipe &
pid=$!
while read x ; do echo "read: $x" ; done < pipe
wait $pid
echo "exit status of bg process: $?"
rm pipe
如果你可以使用直接管道(即不要介意在子shell中运行循环),你可以使用Bash的PIPESTATUS
,它包含管道中所有命令的退出代码:
(echo foo ; exit 19) | while read x ; do
echo "read: $x" ; done;
echo "status: ${PIPESTATUS[0]}"
注意: ls -d / /nosuch
用作下面的示例命令,因为它仍然生成stdout输出( /
)(除了stderr输出)时失败(退出代码1
)。
ccarton的有用答案原则上很有效,但默认情况下, while
循环在子shell中运行,这意味着在循环中创建或修改的任何变量对当前 shell都不可见。
在Bash v4.2 +中 ,您可以通过打开lastpipe
选项来更改此选项 ,这会使管道的最后一段在当前 shell中运行;
在ccarton的回答中, pipefail
选项必须设置为$?
反映管道中第一个失败命令的退出代码:
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输出):
result: [/]; exit code: 1
正如您所看到的,在while
循环中设置的$result
变量是可用的,并且ls
命令的(非零)退出代码反映在$?
。
ikkachu的有用答案很有效,并展示了先进的技术,但它有点麻烦。
这是一个更简单的替代方案:
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),它通常会退出循环。
我们可以用||
来检测这种情况 ,并将退出代码(仍然读入$line
)分配给变量$ec
,然后退出循环。
如果命令的输出没有尾随\\n
, 则需要做更多的工作:
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输出):
result: [no trailing newline]; exit code: 1
一种简单的方法是使用bash pipefail
选项从管道传播第一个错误代码。
set -o pipefail
other_program | while read x; do
echo "Read: $x"
done || echo "Error: $?"
另一种方法是使用coproc
(需要4.0+)。
coproc other_program [args ...]
while read -r -u ${COPROC[0]} col0 col1; do
# [...]
done
wait $COPROC_PID || echo "Error exit status: $?"
coproc
使您不必设置异步性和stdin / stdout重定向,否则您需要在等效的mkfifo
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.