将标准输出捕获到变量并获取前台管道的退出状态

Capture stdout to variable and get the exit statuses of foreground pipe

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

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

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

注:

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

您可以:

  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 保留从最后一个换行符到结尾的部分。为了保留原始 return 状态,我认为需要一些临时变量:

    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
    

备注:

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