管道到头部导致从python调用的shell脚本中的管道损坏

时间:2015-10-08 16:03:53

标签: python bash shell pipe head

我有一个命令,我将运行以生成随机字符串:

var=`< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c8`

当我在交互式bash会话中运行此命令时,我绝对没有错误。但是,当我将此命令放入脚本并将其作为脚本运行时,我得到了由tr指示的Broken pipe错误。我已经阅读了几个相关的主题,但仍然没有答案为什么脚本和交互行为是不同的,有没有办法用shell选项或其他东西来控制它?

编辑I:

关于给出的评论,我发现可以通过以下方式控制管道损坏错误:

 trap - SIGPIPE # to ignore errors

 trap "" SIGPIPE # to display errors

编辑II:

好吧,我提供了有关复制条件的错误信息。最后,似乎问题是python包装器使用os.system()调用脚本:

 python -c "import os; os.system('sh -c \"< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c8\"')"

给定的行会产生与使用过的操作系统无关的管道错误。

编辑III:

此主题已在此处讨论: https://mail.python.org/pipermail/python-dev/2005-September/056341.html

3 个答案:

答案 0 :(得分:5)

如果其中一个父进程陷阱sigpipe,那么管道将继承ignore信号处理,这将导致您遇到此问题。

这可以(安全地)复制:

( trap '' pipe; var=`< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c8 )

通常,head -c8命令很快就会完成,stdin关闭。由于stdin是与stdout的{​​{1}}连接的管道,因此tr写入其tr现在不再有意义了。一旦尝试,系统将使用stdout将其终止。 除非SIGPIPE忽略此信号或已从其父级继承此信号的trignore)处置。然后,SIG_IGNwrite已损坏的tr只会导致定期错误,并将stdout设置为errno,此时EPIPE最多可能会将此错误字符串化并输出到tr并退出。

答案 1 :(得分:1)

This answer提供了从Python到head的管道问题的一个很好的总结,并显示了一些解决方法。

https://stackoverflow.com/a/30091579/456550

答案 2 :(得分:0)

问题似乎是 head 从输入流中读取指定(或默认)行数,打印它们,然后退出。因此,仍在写入的管道中的上游程序发现输出流已关闭。在我看来,这是 head 本身设计的一个限制。您可以改为使用 sed,它读取整个流:sed -n "1,10p" 等效于 head -n10