2016-05-31 52 views
1

我試圖從基於GUI的軟件啓動幾個bash例程 。我面臨的問題是管道問題。 這裏測試的bash腳本(bashScriptTest.sh):斷管錯誤Python子流程

#!/bin/bash 
#---------- Working 
ls | sort | grep d > testFile.txt 
cat testFile.txt 
#---------- NOT working 
echo $RANDOM > testFile2.txt 
for i in `seq 1 15000`; do 
    echo $RANDOM >> testFile2.txt 
done 
awk '{print $1}' testFile2.txt | sort -g | head -1 

而且這裏的Python腳本,創建錯誤:

import subprocess 
# 
with open('log.txt','w') as outfile: 
    CLEAN=subprocess.Popen("./bashScriptTest.sh", stdout=outfile, stderr=outfile) 
    print CLEAN.pid 
    OUTSEE=subprocess.Popen(['x-terminal-emulator', '-e','tail -f '+outfile.name]) 

你可以從運行python腳本看到,遇到斷管錯誤 不在前三個管道(第一行)中,而是在awk完成大量工作之後。 我需要在bash 中管理大量的例程和子例程,並且還使用shell == True標誌不會改變任何事情。 我試圖以最pythonic的方式寫所有東西,但不幸的是沒有 機會我可以重寫python中的所有管道步驟。 另一件要提到的是,如果你測試終端內的bash腳本 一切工作正常。 任何幫助將非常感激。提前致謝!

編輯1:

包含錯誤日誌文件說:

bashScriptTest.sh 
log.txt 
stack.txt 
testFile2.txt 
test.py 
3 
sort: write failed: standard output: Broken pipe 
sort: write error 
+0

請添加錯誤消息和堆棧跟蹤! :) –

+0

你什麼時候等待進程結束? –

+0

@AndréLaszlo我編輯了這個問題! – Mat

回答

1

好了,所以這是一個有點晦澀難懂,但它只是恰巧,我遇到了類似的問題,而跑前段時間研究question on the python-tutor mailing list

當您通過子進程模塊(在python中)直接運行腳本與bash直接運行腳本時看到不同行爲的原因是,python覆蓋了SIGPIGN對所有子進程(全局)的SIG_IGN處置(忽略)。它打印標準輸出從sort命令的第一行後,由於-1標誌

當執行下面的管道......

awk '{print $1}' testFile2.txt | sort -g | head -1 

... head將退出。當sort命令嘗試向其stdout寫入更多行時,會引發SIGPIPE。

SIGPIPE的默認動作;例如,當管道在像bash這樣的shell中執行時;是終止排序命令。如前所述,python用SIG_IGN(忽略)覆蓋缺省操作,所以我們最終會遇到這種奇怪的,有些莫名其妙的行爲。


這一切都很好,但你可能想知道現在該做什麼?這取決於你使用的Python版本...

對於Python 3.2及更高版本,你已經設置好了。 subprocess.Popen in 3.2添加了restore_signals參數,該參數默認爲True,並且無需進一步操作即可有效解決問題。

對於以前的版本,您可以向preexec_fn參數提供一個可調用對象,如...

import signal 
def default_sigpipe(): 
    signal.signal(signal.SIGPIPE, signal.SIG_DFL) 

# ... 

with open('log.txt','w') as outfile: 
    CLEAN=subprocess.Popen("./bashScriptTest.sh", 
          stdout=outfile, stderr=outfile 
          preexec_fn=default_sigpipe) 

我希望有幫助!

編輯:應該注意的是,您的程序實際上可以正常運行,AFAICT就是這樣。您只會看到其他錯誤消息,在shell中直接執行腳本時通常不會看到(由於上述原因)。

另請參見:

+0

真的非常感謝......它解決了我的問題,對於Python來說真的很奇怪。 很高興他們在開發過程中解決了 – Mat

+0

你的'default_sigpipe()'函數改變了全局狀態。我認爲這是一個錯誤。簡單地這樣做一次會產生同樣的效果: 'signal.signal(signal.SIGPIPE,signal.SIG_DFL)' – aramaki