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

red*_*dot 5 python bash shell pipe head

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

var=`< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c8`
Run Code Online (Sandbox Code Playgroud)

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

编辑I:

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

 trap - SIGPIPE # to ignore errors
Run Code Online (Sandbox Code Playgroud)

和

 trap "" SIGPIPE # to display errors
Run Code Online (Sandbox Code Playgroud)

编辑二:

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

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

给定的行产生与使用的OS无关的管道错误.

编辑III:

这个主题在这里讨论过:https: //mail.python.org/pipermail/python-dev/2005-September/056341.html

PSk*_*cik 5

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

这可以(安全地)复制:

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

通常,head -c8命令将很快完成,此时它将stdin关闭.因为它是stdin连接到一个管道stdout中tr,它现在不再是有道理的,tr写它stdout.一旦它尝试,系统将杀死它SIGPIPE.除非tr忽略此信号或从其父级继承此信号的ignore(SIG_IGN)处置.然后,write以tr"打碎stdout只会导致经常出现偏差,并设置errno到EPIPE此时tr很可能会字符串化并输出错误的stderr退出.