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

Bash 捕获stdout到变量并获取前台管道的退出状态,bash,shell,pipe,stdout,exit-code,Bash,Shell,Pipe,Stdout,Exit Code,我想执行一个命令(比如说ls)和sed它的输出,然后将stdout保存到一个变量,如下所示 OUT=$(ls | sed -n -e 's/regexp/replacement/p') 在此之后,如果我尝试访问数组,则只会得到0(这与$?相同)。那么,如何获取$PIPESTATUS以及捕获整个piped命令的stdout呢 注: 如果我只执行那些管道命令而没有捕获stdout(比如ls | sed-n-e's/regexp/replacement/p'),我会在$PIPESTATUS中获得预

我想执行一个命令(比如说
ls
)和
sed
它的输出,然后将stdout保存到一个变量,如下所示

OUT=$(ls | sed -n -e 's/regexp/replacement/p')
在此之后,如果我尝试访问数组,则只会得到
0
(这与
$?
相同)。那么,如何获取
$PIPESTATUS
以及捕获整个piped命令的stdout呢

注:

  • 如果我只执行那些管道命令而没有捕获stdout(比如
    ls | sed-n-e's/regexp/replacement/p'
    ),我会在
    $PIPESTATUS
    中获得预期的退出状态(比如
    0
  • 如果我使用并捕获stdout(如
    OUT=$(ls)
    )只执行单个命令(不使用管道传输多个命令),我将在
    $PIPESTATUS
    中获得预期的单个退出状态(与
    $?
    相同)
另外,我知道,我可以运行命令2次(第一次捕获stdout,第二次访问
$PIPESTATUS
,而不使用命令替换),但是有没有办法在一次执行中同时获得这两个命令?

您可以:

  • 使用临时文件传递管道状态

    tmp=$(mktemp)
    out=$(pipeline; echo "${PIPESTATUS[@]}" > "$tmp")
    PIPESTATUS=($(<"$tmp"))  # Note: PIPESTATUS is overwritten each command...
    rm "$tmp"
    
  • 将输出与pipestatus交错。例如,为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
    
  • 注:

    • 导出的变量应保留按约定使用的大写变量
    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