【问题标题】:How to stop tee to truncate the stdin when using process substitution使用进程替换时如何停止 tee 截断标准输入
【发布时间】: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/null Output is1 73728
  • 几乎值得尝试一个未修改的tee 忽略 SIGPIPE:./RNG | (trap '' PIPE; tee >(test1) >(test2) >(test3) >/dev/null)。但是,我得到的版本继续尝试写入失败的描述符,并且每次失败时都会报告一条消息。这很不优雅;它可能会合法地警告一次,并且一旦失败就应该停止尝试写入描述符。有一个“过程三通”(又名pee)潜伏着——你可以使用它。我写了一个tpipe,它做同样的工作,一旦出现错误,就会优雅地停止写入描述符。

标签: bash shell


【解决方案1】:

teealready support--output-error=warn 的某些版本意味着通过 STDERR 诊断输出错误,但tee 不会因写入管道的错误而退出。不幸的是,我笔记本电脑上的tee 非常基本,所以我无法检查此选项是否满足您的测试用例。

您可能需要将最终的>/dev/null 替换为最长的测试用例,或者使用>(head -c1000G) 之类的东西,否则tee 将永远将数据传送到/dev/null。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 2011-12-11
    相关资源
    最近更新 更多