我想制作这样的Bash脚本管道
prog1 | prog2
这样prog2可以看到prog1的退出代码,并根据该信息采取不同的行动。
这可能吗?
prog2
时进展的控制有限。prog1
prog1
prog2
我想制作这样的Bash脚本管道
prog1 | prog2
这样prog2可以看到prog1的退出代码,并根据该信息采取不同的行动。
这可能吗?
prog2
时进展的控制有限。prog1
prog1
prog2
Answers:
普遍的答案是不。有可能甚至在开始prog2
之前就退出prog1
(显然,如果prog2
实际读取一些输入(如果您在管道中使用它,则希望这样做)就不会发生)。绝对有可能prog2
在此之前退出prog1
;例如,当prog2
某个搜索程序找到匹配项后立即退出时,这种情况就prog1
可能发生,在这种情况下,可能还没有完成所有数据的生成。
没有直接的方法prog2
可以检索prog1
甚至退出的退出状态prog1
。所有这一切prog2
可以知道的是,prog1
已经关闭了其管道,它可以在不死亡做结束。
如果要获取prog1
from 的退出状态prog2
,有两种常用方法:可以将其写入文件,也可以通过管道发送。可以将输出状态作为管道数据的最后一行发送。您必须确保不处理最后一行,直到您知道这是最后一行,即直到您尝试阅读下一行为止。
{ prog1; echo $?; } | …
这是一个示例,其中右侧是一个文本过滤器,该过滤器将包含“错误”一词的每一行变为红色。如果左侧出现故障,则右侧以相同状态退出。
{ prog1; echo $?; } | awk '
NR != 1 {
if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
else print line;
}
{line = $0}
END {exit($0)}
'
${PIPESTATUS[@]}
在的输出中排在其他任何东西之前,这才起作用command
。如果command
打印出一堆数字,或者它可以打印出任意文本,则您会遇到麻烦:您将无法从状态行中区分其输出。
尽管您可以在某些特殊情况下(请参阅其他答案),但并非在每种情况下都可以。一些过滤器程序将继续运行,而其他过滤器程序将保留所有输出,将其一次释放,然后退出。
例如,“将继续前进”程序grep
将作为服务器tail -f /var/log/some_log_file
。sort
在管道中使用会导致“停顿”,因为sort
它将收集输入,直到其前面的管道关闭为止。使用xargs
会增加进一步的复杂性:程序是否由xargs
流水线的一部分启动(可能启动许多实例)?
答案:不直接。
@terdon说明了管道中的上一个命令的退出代码必须作为显式参数发送给下一个命令。
请记住,管道只是前一个命令的STDOUT到下一个命令的STDIN的映射;退出代码不会输出到STDOUT(或STDERR)。
管道中的所有过程均在退出之前启动。因此,prog2
可能必须在启动后获取此信息,也必须推迟处理直到prog1
退出,这可能会使管道停止运行。在执行您的要求时似乎存在根本问题,而不是操作系统限制。
您可能需要考虑一个临时文件,或将结果放入变量中。
使用变量的少量数据示例。
tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
…
else
…
fi
prog2
通常在prog1
完成之前启动,但是有一种方法可以让它在prog1
运行时从其接收输出状态。