bash - 访问 $?带有管道语句的变量?

标签 bash shell sed grep

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

VARIABLE=`grep "searched_string" test.log | sed 's/searched/found/'`

有什么方法可以测试整行(而不仅仅是 sed 命令)是否成功完成?如果我在它之后立即尝试以下代码:

if [ "$?" -ne 0 ]
then 
    echo 1
    exit
fi

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

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

最佳答案

使用

echo ${PIPESTATUS[@]}

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

$ ls | grep . | wc -l
    28
$ echo ${PIPESTATUS[@]}
0 0 0

但是

$ ls | grep nonexistentfilename | wc -l
      0
$ echo ${PIPESTATUS[@]}
0 1 0    #the grep returns 1 - pattern not found

$ ls nonexistentfilename | grep somegibberish | wc -l
ls: nonexistentfilename: No such file or directory
      0
$ echo ${PIPESTATUS[@]}
1 1 0   #ls and grep fails

确切的命令状态

echo ${PIPESTATUS[1]}  #for the grep

这里还有

set -o pipefail

来自文档

pipefail

If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

$ 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

根据评论编辑

您可能尝试了下一个:

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

当然,这是行不通的,因为整个 $(...) 部分都在子 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
)

还有,注释的第二行是解决方案,eg:

var_with_status=$(command | commmand2 ; echo ":DELIMITER:${PIPESTATUS[@]}")

现在,$var_with_status 不仅包含命令的结果 | command2 但 PIPESTATUS 也是,用一些独特的分隔符分隔,所以你可以提取它......

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

您也可以将 PIPESTATUS 写入某个临时文件(在子 shell 中),父级可以读取它并删除临时文件...

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

...小心不要掉进XY problem ,您将在其中制作极其复杂的脚本,只是因为您不想更改处理逻辑。

例如您始终可以将脚本分成安全的部分,例如:

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

够简单吗?

所以,问问自己 - 您真的需要弄清楚如何从子 shell 中获取 PIPESTATUS 吗?

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

关于bash - 访问 $?带有管道语句的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25798851/

相关文章:

linux - Grep 中的行编号

bash - grep 使用另一个 csv 或 txt 文件作为输入的 csv 文件

regex - 如何在 unix (osx) 中搜索/替换一堆文本文件

linux - 在 AWK 中可移植地处理任意参数

shell - jenkins 构建失败 shell 命令权限被拒绝

perl - 寻找 Perl 或 sed 单行代码来用另一个文件的内容替换字符串

sed 多行替换

json - 使用jq添加JSON对象时如何防止转义?

linux - 将文件夹中的所有文件名传递给 bash 脚本,添加特殊附录

bash - 使用 bash 或并行 GNU 在 bash 中进行并行测试