【问题标题】:Maintain exit code from bash command despite output being piped through sed尽管输出通过 sed 管道传输,但仍保持 bash 命令的退出代码
【发布时间】:2021-05-20 08:04:23
【问题描述】:

我刚刚注意到,即使编译失败,我的一些 CI 作业也返回了 OK。这本质上是因为调用 bash 命令来编译代码,虽然失败并返回 1,但它的输出通过sed 管道传输以向输出添加一些颜色等。

本质上,这归结为以下内容

$ false; echo $? # returns 1
$ true; echo $? # returns 0
$ false | sed 's/^/OUTPUT: /' # returns 0 because sed returns 0
$ true | sed 's/^/OUTPUT: /' # returns 0 because sed returns 0

我知道在 bash 上有PIPESTATUS,所以我可以使用${PIPESTATUS[0]} 来获取在管道之前运行的命令的退出代码。但是我如何对任何命令进行包装,以便将其输出通过管道传输到 sed,然后返回命令本身的退出代码(丢弃 sed 的退出代码)?

为了使它真正通用,假设我想通过管道将任何命令的输出传递给 sed,以便在每行输出之前添加一个彩色前缀:

$ PREFIX="$(printf '\033[1;31m')OUTPUT: $(printf '\033[0m')"
$ ls | sed "s/^/$PREFIX/"

如上所述,由于到sed 的管道,无论ls 返回什么,它都会返回0,并且将显示目录内容,每行前面都有一个红色OUTPUT:

我可以定义一个函数、别名等(我们称之为“包装”)来让我调用例如wrap ls *.txt 以这样的方式执行 ls *.txt,通过 sed 模式管道输出,并返回 ls *.txt 本身的退出代码,以便

$ wrap ls *.txt
OUTPUT: file1.txt
OUTPUT: file2.txt
$ echo $? # displays 0 (assuming there is at least one .txt file)
$ wrap ls *.foo
ls: No such file or directory
$ echo $? # displays 1 (assuming there is NO .foo file)

【问题讨论】:

  • set -o pipefail? Do not parse ls。或者只是command > >(sed 's/^/OUTPUT: /')
  • 一个愚蠢的 hack 是 whatever | sed whatever | grep . 如果没有来自 sed 的输出则失败。这显然只有在您总是期望 sed 脚本的输出时才有效,或者即使第一个命令失败也可能产生部分结果。
  • @JHH :输出是什么意思?标准输出、标准错误或两者兼有?
  • @user1934428 只是标准输出。

标签: bash sed pipe exit-code pipestatus


【解决方案1】:

试试:

function wrap
{
    "$@" | sed 's/^/OUTPUT: /'
    return "${PIPESTATUS[0]}"
}

【讨论】:

    猜你喜欢
    • 2011-06-25
    • 2011-10-15
    • 2018-08-18
    • 2012-02-29
    • 2018-01-25
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    相关资源
    最近更新 更多