簡體   English   中英

從終端運行並從Python運行時,腳本的工作方式不同

[英]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 (這將有利地取代foldhead ):

#!/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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM