【问题标题】:Capture stdout to variable and get the exit statuses of foreground pipe将标准输出捕获到变量并获取前台管道的退出状态
【发布时间】:2020-05-07 12:29:04
【问题描述】:

我想执行一个命令(比如ls)和sed它的输出,然后将stdout保存到一个变量中,像这样,

OUT=$(ls | sed -n -e 's/regexp/replacement/p')

在此之后,如果我尝试访问$PIPESTATUS 数组,我只会得到0(与$? 相同)。那么,我怎样才能同时获得$PIPESTATUS 以及捕获整个管道命令的标准输出?

注意:

  • 如果我只执行那些管道命令并且没有捕获标准输出(如 ls | sed -n -e 's/regexp/replacement/p'),我会在 $PIPESTATUS 中获得预期的退出状态(如 0 0
  • 如果我只使用Command Substitution 执行单个命令(没有管道多个命令)并捕获标准输出(如OUT=$(ls)),我会在$PIPESTATUS 中得到预期的single 退出状态(即同$?)

附:我知道,我可以运行该命令 2 次(第一次捕获标准输出,第二次访问 $PIPESTATUS 而不使用命令替换),但是有没有办法在一次执行中同时获得两者?

【问题讨论】:

    标签: bash shell pipe stdout exit-code


    【解决方案1】:

    你可以:

    1. 使用临时文件传递 PIPESTATUS。

      tmp=$(mktemp)
      out=$(pipeline; echo "${PIPESTATUS[@]}" > "$tmp")
      PIPESTATUS=($(<"$tmp"))  # Note: PIPESTATUS is overwritten each command...
      rm "$tmp"
      
    2. 使用临时文件传递out

      tmp=$(mktemp)
      pipeline > "$tmp"
      out=$(<"$tmp"))
      rm "$tmp"
      
    3. 将输出与管道状态交错。例如,为 PIPESTATUS 保留从最后一个换行符到结尾的部分。为了保持原始返回状态,我认为需要一些临时变量:

      out=$(pipeline; tmp=("${PIPESTATUS[@]}") ret=$?; echo $'\n' "${tmp[@]}"; exit "$ret"))
      pipestatus=(${out##*$'\n'})
      out="${out%$'\n'*}"
      out="${out%%$'\n'}" # remove trailing newlines like command substitution does
      

      测试:

      out=$(false | true | false | echo 123; echo $'\n' "${PIPESTATUS[@]}");
      pipestatus=(${out##*$'\n'});
      out="${out%$'\n'*}"; out="${out%%$'\n'}";
      echo out="$out" PIPESTATUS="${pipestatus[@]}"
      # out=123 PIPESTATUS=1 0 1 0
      

    注意事项:

    • 按照惯例,大写变量应由导出的变量保留。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-16
      • 2019-04-10
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 2018-01-10
      • 2018-08-10
      相关资源
      最近更新 更多