sence:python中使用subprocess.Popen(cmd, stdout=sys.STDOUT, stderr=sys.STDERR, shell=True) ,stdout, stderr 為None.
在錯誤中執行是無法捕獲 stderr的內容,後面將上面的改為 subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
,發現是可以拿到 stderr
, 但是會遇到大量任務hanging,造成線上事故。
為此特意查詢subprocess
的一些引數的說明。
stdin
stdout
stderr
如果這些引數為PIPE
, 此時會為一個檔案控制程式碼,而傳入其他(例如sys.stdout
、None
等)的則為None
正如這裡介紹的一樣,subprocess 。
而使用 PIPE
,卻導致程式 hanging。一般來說不推薦使用 stdout=PIPE
stderr=PIPE
,這樣會導致一個死鎖,子程式會將輸入的內容輸入到 pipe
,直到作業系統從buffer中讀取出輸入的內容。
查詢手冊可以看到確實是這個問題 Refernce
Warning This will deadlock when using
stdout=PIPE
and/orstderr=PIPE
and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Usecommunicate()
to avoid that.
而在linux中 PIPE
的容量(capacity)是核心中具有固定大小的一塊緩衝區,如果用來接收但不消費就會阻塞,所以當用來接收命令的輸出基本上100% 阻塞所以會導致整個任務 hanging。( -Linux2.6.11 ,pipe capacity 和system page size 一樣(如, i386 為 4096 bytes )。 since Linux 2.6.11+,pipe capacity 為 65536 bytes。)
關於更多的資訊可以參考:pipe
所以如果既要拿到對應的輸出進行格式化,又要防止程式hang,可以自己建立一個緩衝區,這樣可以根據需求控制其容量,可以有效的避免hanging。列如:
cmd = "this is complex command"
outPipe = tempfile.SpooledTemporaryFile(bufsize=10*10000)
fileno = outPipe.fileno()
process = subprocess.Popen(cmd,stdout=fileno,stderr=fileno,shell=True)
另外,幾個引數設定的不通的區別如下:
stdout=None
為繼承父程式的控制程式碼,通俗來說為標準輸出。
stderr=STDOUT
重定向錯誤輸出到標準輸出
stdout=PIPE
將標準輸出到linux pipe
Reference