【问题标题】:Access $? Variable with a piped statement?访问 $?带有管道语句的变量?
【发布时间】:2014-09-12 00:16:34
【问题描述】:

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

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

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

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

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

有人能说明如何解决这个问题吗?

【问题讨论】:

标签: bash shell sed grep


【解决方案1】:

使用

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

来自文档

管道故障

如果设置,管道的返回值是 最后一个(最右边的)命令以非零状态退出,如果退出则为零 管道中的所有命令都成功退出。这个选项是 默认禁用。

$ 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
)

另外,注释的第二行是一个解决方案,例如:

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

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

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

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

也可以将 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

够简单吗?

所以,问问你自己 - 你真的需要琢磨如何让 PIPESTATUS 形成一个子外壳吗?

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

【讨论】:

  • 但是,我在整个 VARIABLE= 部分遇到了问题。这使得它没有给我想要的管道输出......有什么办法吗?
猜你喜欢
  • 1970-01-01
  • 2013-09-06
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多