访问$?带有管道声明的变量?

jj1*_*172 2 bash shell grep sed

我有一些代码,我想要$?变量.

VARIABLE=`grep "searched_string" test.log | sed 's/searched/found/'`
Run Code Online (Sandbox Code Playgroud)

有没有办法测试整条线(而不仅仅是sed命令)是否成功完成?如果我在它之后尝试以下代码:

if [ "$?" -ne 0 ]
then 
    echo 1
    exit
fi
Run Code Online (Sandbox Code Playgroud)

即使语句的grep部分失败,它也不会运行.

有人可以展示如何解决这个问题吗?

jm6*_*666 7

使用

echo ${PIPESTATUS[@]}
Run Code Online (Sandbox Code Playgroud)

将打印出所有命令的退出状态数组.

$ ls | grep . | wc -l
    28
$ echo ${PIPESTATUS[@]}
0 0 0
Run Code Online (Sandbox Code Playgroud)

$ ls | grep nonexistentfilename | wc -l
      0
$ echo ${PIPESTATUS[@]}
0 1 0    #the grep returns 1 - pattern not found
Run Code Online (Sandbox Code Playgroud)

要么

$ ls nonexistentfilename | grep somegibberish | wc -l
ls: nonexistentfilename: No such file or directory
      0
$ echo ${PIPESTATUS[@]}
1 1 0   #ls and grep fails
Run Code Online (Sandbox Code Playgroud)

确切的命令状态

echo ${PIPESTATUS[1]}  #for the grep
Run Code Online (Sandbox Code Playgroud)

这里也是

set -o pipefail
Run Code Online (Sandbox Code Playgroud)

来自文档

pipefail

如果设置,则管道的返回值是以非零状态退出的最后(最右侧)命令的值,如果管道中的所有命令都成功退出,则返回零.默认情况下禁用此选项.

$ ls nonexistentfile | wc -c
ls: nonexistentfile: No such file or directory
        0 
$ echo $?
0

$ set -o pipefail
$ ls nonexistentfile | wc -c
ls: nonexistentfile: No such file or directory
        0 
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)

根据评论编辑

你可能尝试了下一个:

VARIABLE=$(grep "searched_string" test.log | sed 's/searched/found/')
echo "${PIPESTATUS[@]}"
Run Code Online (Sandbox Code Playgroud)

当然,这不起作用,因为整个$(...)部分在子shell(另一个进程)中运行,因此当子shell退出时,所创建的任何变量都会丢失.(在))

您应该将整个PIPESTATUS机制放入$(...)下一个:

variable=$(
        grep "searched_string" test.log | sed 's/searched/found/'

        # do something with PIPESTATUS
        # you should not echo anythig to stdout (because will be captured into $variable)
        # you can echo on stderr - e.g.
        echo "=${PIPESTATUS[@]}=" >&2
)
Run Code Online (Sandbox Code Playgroud)

此外,评论的第二行是一个解决方案,例如:

var_with_status=$(command | commmand2 ; echo ":DELIMITER:${PIPESTATUS[@]}")
Run Code Online (Sandbox Code Playgroud)

现在,它$var_with_status不仅包含command | command2了PIPESTATUS 的结果,还包含了一些独特的分隔符,因此你可以提取它...

此外,set -o pipefail将显示结果 - 如果您不需要确切的失败位置.

你也可以在一些临时文件中写入PIPESTATUS(在子shell中),父级可以读取它并删除临时文件......

也可以将PIPESTATUS打印到子shell中的不同文件描述符中,并在父shell中读取此描述符,但....

...要注意不要陷入XY问题,在那里你会制作极其复杂的脚本,只因为你不想改变处理的逻辑.

例如,你总是可以将脚本分成安全的部分,例如:

var1=$(grep 'str' test.log)
#check the `$var1` and do something with the error indicated with `$?`
var2=(sed '....' <<<"$var1")
#check the `$var2` and do something with the error indicated with `$?`
#and so on
Run Code Online (Sandbox Code Playgroud)

够简单吗?

所以,问问自己 - 你真的需要如何让PIPESTATUS成为子壳吗?

Ps:不要使用大写变量名.可能会干扰某些环境变量并导致难以调试的问题.