$ head -c10G /dev/zero |
tee >(head -c1M | wc -c) >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)
给出:
1048576
1064960
1064960
1064960
我本来期望:
1048576
10485760
104857600
1048576000
我想这是由于head -c1M
关闭管道,tee
然后只向其他进程写入一个块,然后发现它无法写入第一个进程然后退出。
我可以要求tee
跳过已关闭的收件人,但继续写信给其他收件人吗?
答案1
你应该使用tee --output-error=exit-nopipe
.这将忽略SIGPIPE
信号和EPIPE
写入错误,但仍会因任何其他错误而死亡。
tee --output-error=exit-nopipe
,就像warn
您答案中的变体一样,当它无法写入至少一个输出时,它会退出;但它确实将标准输出算作其中之一。
您的示例有错误,因为它们只是将输出转储head -c10G /dev/zero | tee ...
到您的终端(您看不到,因为空字节是“不可见的”);这就是为什么tee
你的答案不退出:因为在>(...)
进程替换退出后它仍然会写入标准输出。
对于没有 GNU tee 的系统,可能的解决方法是将 a 附加到通过管道传输到cat >/dev/null
的命令中tee
;但你不能对所有这些都这样做;您必须决定“主”输出,tee
如果写入不成功,该输出将导致退出。例子:
$ dd if=/dev/zero |
tee >(dd of=/dev/null count=200; cat >/dev/null) >(dd of=/dev/null count=700; cat >/dev/null) |
dd of=/dev/null count=1000
$ dd if=/dev/zero |
tee >(dd of=/dev/null count=1000) >(dd of=/dev/null count=700; cat >/dev/null) |
{ dd of=/dev/null count=200; cat >/dev/null; }
两者应该分别写入 200、700 和 1000 个块。
答案2
好像--output-error=warn
是有这个功能
head -c10G /dev/zero |
tee --output-error=warn >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)
不幸的是,它还会在 stderr 上发送垃圾邮件警告,并且如果无法写入其中任何一个,则它不会退出。
答案3
碰巧任何阻塞的管道都会发送 SIGPIPEtee
并停止它:
$ head -c10G /dev/zero | tee >(head -c10 | wc -c) >(head -c1M | wc -c)
10
65536
该命令tee
从第一个管道接收 SIGPIPE 并导致所有子管道退出。
您需要扩展每个管道以使其没有限制:
$ head -c10G /dev/zero | tee >({ head -c10 | wc -c; }; cat >/dev/null ) >(head -c1M | wc -c)
10
1048576
对于您给出的所有案例:
$ head -c10G /dev/zero | tee >({ head -c1M | wc -c;}; cat >/dev/null) >({ head -c10M | wc -c; }; cat >/dev/null) >( { head -c100M | wc -c; }; cat>/dev/null) >(head -c1000M | wc -c)
1048576
10485760
104857600
1048576000
但使用以下选项可以更简单地tee
避免因管道错误而退出-p
:
$ head -c10M /dev/zero | tee -p >(head -c10 | wc -c) >(head -c100 | wc -c) >(head -c1000| wc -c) >(head -c1M | wc -c)
100
1000
10
1048576
这可能会打印乱序。