![](/img/trans.png)
[英]Script works in terminal but not when ran using ProcessBuilder
[英]Script works differently when ran from the terminal and ran from Python
我有一個簡短的bash腳本foo.sh
#!/bin/bash
cat /dev/urandom | tr -dc 'a-z1-9' | fold -w 4 | head -n 1
當我直接從shell運行它時,它運行正常,完成時退出
$ ./foo.sh
m1un
$
但是當我從Python運行它時
$ python -c "import subprocess; subprocess.call(['./foo.sh'])"
ygs9
它輸出線但然后永遠掛起。 造成這種差異的原因是什么?
將trap -p
命令添加到bash腳本,停止掛起的python進程並運行ps
顯示正在發生的事情:
$ cat foo.sh
#!/bin/bash
trap -p
cat /dev/urandom | tr -dc 'a-z1-9' | fold -w 4 | head -n 1
$ python -c "import subprocess; subprocess.call(['./foo.sh'])"
trap -- '' SIGPIPE
trap -- '' SIGXFSZ
ko5o
^Z
[1]+ Stopped python -c "import subprocess; subprocess.call(['./foo.sh'])"
$ ps -H -o comm
COMMAND
bash
python
foo.sh
cat
tr
fold
ps
因此, subprocess.call()
執行命令,並屏蔽SIGPIPE
信號。 當head
完成其工作並退出時,其余進程不會收到損壞的管道信號並且不會終止。
解釋了手頭的問題,很容易在python bugtracker中找到bug,結果證明是問題#1652 。
Python 2以非標准的方式處理SIGPIPE
的問題(即被忽略)已經在Leon的答案中被創造出來了,修復在鏈接中給出:將SIGPIPE
設置為默認值( SIG_DFL
),例如,
import signal
signal.signal(signal.SIGPIPE,signal.SIG_DFL)
您可以嘗試從腳本中取消設置SIGPIPE
,例如,
#!/bin/bash
trap SIGPIPE # reset SIGPIPE
cat /dev/urandom | tr -dc 'a-z1-9' | fold -w 4 | head -n 1
但是,不幸的是,根據Bash參考手冊 ,它不起作用
進入shell時忽略的信號不能被捕獲或重置。
最后的評論:你在這里使用了無用的cat
; 最好將腳本編寫為:
#!/bin/bash
tr -dc 'a-z1-9' < /dev/urandom | fold -w 4 | head -n 1
然而,既然你正在使用Bash,你也可以使用如下內置的read
(這將有利地取代fold
和head
):
#!/bin/bash
read -n4 a < <(tr -dc 'a-z1-9' < /dev/urandom)
printf '%s\n' "$a"
事實證明,使用此版本,您將清楚地知道發生了什么(並且腳本不會掛起):
$ python -c "import subprocess; subprocess.call(['./foo'])"
hcwh
tr: write error: Broken pipe
tr: write error
$
$ # script didn't hang
(當然,它適用於Python3沒有錯誤)。 告訴Python使用SIGPIPE
的默認信號也很有效:
$ python -c "import signal; import subprocess; signal.signal(signal.SIGPIPE,signal.SIG_DFL); subprocess.call(['./foo'])"
jc1p
$
(也適用於Python3)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.