python subprocessモジュールを用いてシステムからプログラム実行状態の戻り値を取得する方法

4233 ワード

最近、ツールを作成する際に難しい問題に遭遇しました.linux開発環境では静的言語プログラムを自動化して一括コンパイルし、コンパイル結果に基づいて一定の操作を実行する必要がありますが、bash呼び出しコンパイラのbinプログラムはファイルをコンパイルした後の状態が少し難しいです.最初に思いついた方法は、直接ツールに死を書くことです.
import os
os.system('gcc <_file> ;echo $?')

コンパイルコマンドを実行した直後にecho$を実行しますか?コマンド取得前のコマンドgccの状態は値を返し、コンパイルに誤りがない場合は標準出力0、異常の場合はコンパイルに失敗した標準エラー出力、echoが取得した状態コードを同時に標準出力する.
stanpao@vm:~$ gcc haha ;echo $?
/usr/bin/ld:haha: file format not recognized; treating as linker script
/usr/bin/ld:haha:1: syntax error
collect2: error: ld returned 1 exit status
1

システムメソッドでは標準出力しか取得できないのは明らかですが、標準出力からコンテンツを抽出することはできません.OSを使うと思っている人もいるかもしれません.popen()bashコマンドを実行すると、ファイルオブジェクトに戻り、最後の行のステータスコードを解析的に抽出できます.
import os
print('the status code is:',os.popen('gcc haha;echo $?').readlines()[-1])
----------------------------
stanpao@vm:~$ python test.py 
/usr/bin/ld:haha: file format not recognized; treating as linker script
/usr/bin/ld:haha:1: syntax error
collect2: error: ld returned 1 exit status
('the status code is:', '1
')

このようにしても、プログラムの実行ステータスコードを取得することは確かであるが、echoの前に別のネーミングを実行すると、プログラムの実行ステータスコードの正常な取得に影響を及ぼすことは容易ではない.例えば、コンパイラが実行する異常出力を日志文書に書く必要があり、コマンド'>>log'を使用して情報を追加し、明らかに標準出力のリダイレクトとして、このコマンドはpopenの後にのみ使用できます.
import os
print('the status code is:',os.popen('gcc haha >> log;echo $?').readlines()[-1])
-----------------------------
stanpao@vm:~$ python test.py 
/usr/bin/ld:haha: file format not recognized; treating as linker script
/usr/bin/ld:haha:1: syntax error
collect2: error: ld returned 1 exit status
('the status code is:', '1
') stanpao@vm:~$ more log stanpao@vm:~$

異常出力は残っていますが、標準入力が正しくファイルに書き込まれていません.teeがlogにリダイレクトしてみてください.
import os
print('the status code is:',os.popen('gcc haha | tee -a log ; echo $?').readlines()[-1])
----------------------------
stanpao@vm:~$ python test.py 
/usr/bin/ld:haha: file format not recognized; treating as linker script
/usr/bin/ld:haha:1: syntax error
collect2: error: ld returned 1 exit status
('the status code is:', '0
') stanpao@vm:~$ more log stanpao@vm:~$

このとき、コマンドラインにある原因は、異常ログ情報の標準エラー出力を正しく取得できないだけでなく、ステータスコード1もteeコマンドを正しく実行するためエラーで0として記録する.bashコマンドの観点からプログラムの実行状態を取得するのは、効率的で簡単ではないことは明らかです.ここではpythonの強力なsubprocessモジュールについて説明します.
import subprocess
compilePopen = subprocess.Popen('gcc haha',shell=True,stderr=subprocess.PIPE)
compilePopen.wait()
print('the status code is:',compilePopen.returncode)
with open('log','w') as object:
	object.write(compilePopen.stderr.read())
-----------------------------
stanpao@vm:~$ python test.py 
('the status code is:', 1)
stanpao@vm:~$ more log 
/usr/bin/ld:haha: file format not recognized; treating as linker script
/usr/bin/ld:haha:1: syntax error
collect2: error: ld returned 1 exit status
stanpao@vm:~$ 

このことから,subprocessを用いることでbashコマンドの呼び出しを簡略化するだけでなく,標準出力コンテンツとサブルーチンの状態戻りコードを効率的に取得することができる.subprocessモジュールの基本的な使い方を紹介します.このモジュールでは,Popenはベースクラスであり,他の方法はパラメータの多いPopen上にカプセル化して具体的な簡単な機能を実現する.class Popen(args,bufsize=0,executable=None,stdin=None,stdout=None,stderr=None,preexec_fn=None,close_fds=False,shell=False,cwd=None,env=None,universal_newlines=False,startupinfo=None,creationflags=0)args:shellコマンド、文字列、またはシーケンスタイプ、例えばlist,tuple.bufsize:バッファサイズ、デフォルトstdin、stdout、stderr:プログラムの標準入力、標準出力、および標準エラーshell:Trueは、shellコマンドを文字列全体で表すことができます.Falseの場合、shellコマンドはsplitシーケンスcwdにします.サブプロセスを設定する前のディレクトリenv:サブプロセスを指定する環境変数です.env=Noneの場合、デフォルトでは親プロセスから環境変数universal_が継承されます.newlines:システムによって改行が異なり、このパラメータがtrueに設定されている場合は改行として使用されることを示します
Popenクラスはオブジェクトインスタンスを生成し、特定のサブプログラムを実行することを指定した後、クラスメソッドwait()を使用してサブプログラムの終了を待機し、サブプログラムがステータスコードを返し、PopenオブジェクトのreturnCode属性として記録されるなどのサブプログラム関連情報を取得する必要がある.Popenクラスでstdoutとstdinを指定することでサブルーチンに関する標準出力入力ソースを指定できるが、これらの入力出力内容を読み書き修正する必要がある場合は、特殊パラメータsubprocessを指定する必要がある.PIPEは、コンテンツをパイプキャッシュに組み入れる、Popenオブジェクトに対応する属性からその対応するファイルオブジェクトを取得し、上記コードstderr=subprocessを参照して読み出し修正操作を行う.PIPEおよびcompilePopen.stderrセクションで、compilePopenがPopenオブジェクトです.