【问题标题】:Getting the status of the first command in a pipe when running under timeout在超时下运行时获取管道中第一个命令的状态
【发布时间】:2021-08-14 06:47:41
【问题描述】:

我编写了一个管道命令并尝试在timeout 下运行它。如果最后一个管道命令成功但第一个不成功,则状态为 0(因为最后一个命令成功)。 我读了这篇关于使用PIPESTATUS 获取状态的帖子:Pipe output and capture exit status in Bash(它还建议使用set -o pipefail,但它也不起作用)。但是,当我尝试在超时下运行它时,PIPESTATUS[0] 不正确,这可能是因为在timeout 下运行它时我需要使用bash -c 运行管道命令(下一篇文章解释了为什么@987654329 @语法应该使用Why does `timeout` not work with pipes?)

代码示例:

function func {
    HELLO="hello"
    DOES_NOT_EXIST="does_not_exist.txt"
    CMD="ls $DOES_NOT_EXIST | echo $HELLO"
    echo $CMD
    timeout 5 bash -c "$CMD"
    echo ${PIPESTATUS[0]}
}

#main
func

输出:

ls does_not_exist.txt | echo hello
hello
ls: cannot access does_not_exist.txt: No such file or directory
0  

最后一行是echo hello的状态,而不是ls的失败状态(我没记错的话应该是2)。有没有办法获取管道中第一个命令的状态? (我的实际需要是获取第一个管道命令的状态,无论它是否失败)

【问题讨论】:

  • $PIPESTATUS 仅获取当前 shell 运行的命令的状态。您正在使用 bash -c 的不同 bash 进程中运行命令

标签: bash


【解决方案1】:

我在 bash 命令行下尝试过,它似乎工作正常:

$ { echo foo; exit 2; } | grep foo
foo
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}
2 0
$ { echo foo; exit 18; } | grep bar
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}
18 1
$ timeout 5 bash -c '{ echo foo; exit 18; } | grep bar; echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}'
18 1
$ timeout 5 bash -c '{ echo foo; exit 18; } | grep foo; echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}'
foo
18 0

【讨论】:

  • 尝试编写您的脚本timeout bash -c '{ sleep 6;echo foo; exit 18; } | grep bar; echo "${PIPESTATUS[@]}" 来演示尚未成功处理的案例。
【解决方案2】:

timeout 5 bash -c "$CMD" 在另一个进程中运行管道。子进程无法更改其父进程的变量,因此您不能在bash -c 之外使用PIPESTATUS

要在同一进程中运行管道,可以在管道中的每个命令前加上timeout

timeout 5 firstCmd | timeout 5 secondCmd
declare -p PIPESTATUS

【讨论】:

    猜你喜欢
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多