将stdout捕获到变量中并获取前台管道的退出状态

3
我想执行一个命令(比如 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
  • 如果我只执行单个命令(不使用多个命令进行管道处理)并使用命令替换捕获标准输出(如OUT=$(ls)),则我可以在$PIPESTATUS中得到期望的单个退出状态(与$?相同)
附言:我知道我可以运行两次命令(首先捕获标准输出,然后在不使用命令替换的情况下访问$PIPESTATUS),但有没有一种方法可以在单个执行中同时获取两者?
1个回答

2
你可以:
  1. Use a temporary file to pass PIPESTATUS.

    tmp=$(mktemp)
    out=$(pipeline; echo "${PIPESTATUS[@]}" > "$tmp")
    PIPESTATUS=($(<"$tmp"))  # Note: PIPESTATUS is overwritten each command...
    rm "$tmp"
    
  2. Use a temporary file to pass out.

    tmp=$(mktemp)
    pipeline > "$tmp"
    out=$(<"$tmp"))
    rm "$tmp"
    
  3. Interleave output with pipestatus. For example reserve the part from last newline character till the end for PIPESTATUS. To preserve original return status I think some temporary variables are needed:

    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
    

    tested with:

    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
    

注意事项:

  • 按照惯例,大写变量应该被保留为导出变量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接