tee发送不完整的数据

tee发送不完整的数据
$ 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

这可能会打印乱序。

相关内容