【发布时间】:2015-11-19 08:11:49
【问题描述】:
我正在测试随机数生成器,我需要将它的输出传递给各种测试。由于与测试相比,RNG 相对较慢,并且我需要测试 0.5-1TB 的数据,因此我想出了使用 tee 将数据从 RNG 传递到所有测试的想法。主要的好处是我只需要生成数据。命令是
./RNG | tee >(test1) >(test2) >(test3) >/dev/null
但是,它没有按预期工作。例如,当 test1 完成时, tee 将停止所有其他测试,即使他们需要更多数据才能完成。
你可以通过命令看到问题:
cat /dev/zero | tee >(head -c200M | md5sum) >(head -c10M | sha1sum) | wc -c
输出为:10559568
我希望 tee 会在所有子进程完成后完成,但事实并非如此。它将在第一个进程完成后停止(在本例中为 head -c10M | sha1sum)。我能做些什么来改变这种行为?
【问题讨论】:
-
我认为这与this question中描述的问题有关。
-
tee在其中一个写入结束关闭管道时关闭管道(并因此得到SIGPIPE),这反过来导致RNG结束时的SIGPIPE。只要管道在写入端没有关闭,您就不会遇到这个问题。例如,这可以通过; cat >/dev/null轻松实现。试试cat /dev/zero | tee >(head -c200M | sha1sum) >(head -c10M | sha1sum; cat >/dev/null) | wc -c,你会得到209781760。 -
建议的 WA 仅在知道哪个测试将消耗大部分数据时才有效。我真正想要的是
tee只要至少有一个管道打开就可以继续,并避免输出到标准输出。我可以通过编辑tee源代码来实现这一点。这很容易 - 我添加了signal (SIGPIPE, SIG_IGN);并注释掉了以下代码if (fail) { error (output_error == output_error_exit || output_error == output_error_exit_nopipe, w_errno, "%s", files[i]); }以及打开 stdout 进行编写。我会要求tee开发人员为此添加一个命令行开关。 -
顺便说一句,我现在有更好的测试用例来说明问题:
cat /dev/zero | tee >(head -c200M | wc -c ) >(head -c1 | wc -c) >/dev/nullOutput is1 73728 -
几乎值得尝试一个未修改的
tee忽略 SIGPIPE:./RNG | (trap '' PIPE; tee >(test1) >(test2) >(test3) >/dev/null)。但是,我得到的版本继续尝试写入失败的描述符,并且每次失败时都会报告一条消息。这很不优雅;它可能会合法地警告一次,并且一旦失败就应该停止尝试写入描述符。有一个“过程三通”(又名pee)潜伏着——你可以使用它。我写了一个tpipe,它做同样的工作,一旦出现错误,就会优雅地停止写入描述符。