在bash shell脚本中将管道与退出状态组合在一起

时间:2011-09-09 11:30:45

标签: bash shell pipe exit-code

我有这个 bash shell-script命令,如果 make 成功,则会导致 date 运行(终止时退出状态为零),反之亦然:

make && date

但现在我想处理它的输出,例如。

make | sed s/a/A/

如果我这样做

make | sed s/a/A/ && date

日期即使 make 失败也会运行。

如果我改为

make && date | sed s/a/A/
sed 处理 date 的输出而不是 make

你知道任何解决方案吗?谢谢!


P.S。我试过这些:

(make | sed s/a/A/) && date
make 失败时,

date 仍在运行。

(make && (date > /dev/null)) | sed s/a/A/
make 成功时,

date 不会运行。

3 个答案:

答案 0 :(得分:10)

如果你确实有一个带有进程替换的shell(bash没有,posix shell不是),而不是

make > >(sed s/a/A/) && date

应该做的伎俩,除了bash它不等待sed(似乎zsh确实如此,但我只尝试过它,没有检查过doc),所以date的输出可以在sed输出的最后一行之前得到。在普通的posix shell中,你可以使用更复杂的构造

((make && date >&3) | sed s/a/A/) 3>&1

在sed处理完所有内容之前,日期可以再次运行,因此它的输出可以再次出现在sed输出的最后一行之前。

如果您希望日期仅在sed处理完所有内容后运行,那么您唯一的机会就是将make状态存储在某处。类似的东西:

(make && touch make-succeeded) | sed s/a/A/
rm make-succeeded 2>/dev/null && date

滥用这个事实,如果该文件不存在,rm(不带-f)将以非零状态退出并使用重定向来消除它的错误消息。正如弗雷德里克所提到的那样,bash确实有一个存放出口状态的地方,所以在bash你可以:

make | sed s/a/A/
[ 0 -eq $PIPESTATUS[0] ] && date

答案 1 :(得分:8)

启用pipefail子shell中的make

(set -o pipefail; make 2>/dev/null | sed s/a/A/) && date

答案 2 :(得分:1)

基本上是这样的;

my_make () {
  local rc
  make >tmp
  rc=$?
  sed s/a/A/ tmp
  rm tmp
  return $rc
}

显然应该以适当的方式处理临时文件;为了集中讨论手头的问题,这是愚蠢的。如果你对文件描述符很聪明,你可能会完全避免使用临时文件,但它是星期五,我需要更多的咖啡。