通过管道进入while循环获取流程替换的退出代码 [英] Get exit code of process substitution with pipe into while loop

查看:122
本文介绍了通过管道进入while循环获取流程替换的退出代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下脚本调用另一个程序在while循环中读取其输出(请参见

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 $?, the ls 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆