Help us understand the problem. What is going on with this article?

subprocessについて調べたメモ

この記事は古いです.別記事で更新しました.

こちら.https://qiita.com/HidKamiya/items/e192a55371a2961ca8a4
ここではとりあげていないsubprocess.run()subprocess.Popen()などを中心に,より広くまとめました.

非推奨コマンド

  • os.system(cmd) #サブシェル内コマンド実行(コマンドラインでsh -c "cmd"とするのと同様) #終了ステータス
  •  .spawn{lvpe}(mode,path/file) #path実行。mode: os.P_.. #l/v:固定/可変長引数、p:環境変数PATH内探索、e:現プロセス環境引継
  •  .popen(cmd,mode) #外部プロセス(スクリプト、ソフトなど)へ通信。読み書き(mode:'r','w') #pipe open?
  •  .exec{lvpe}(path/file) #プロセス置換
  • commands.getstatusoutput(cmd) #(終了ステータス、結果)
  •      .getoutput(cmd) #結果

概要

  • subprocess.call(cmd) #終了ステータス
  •      .check_call(cmd) #終了ステータス but エラー時例外(CalledProcessError)
  •      .check_output(cmd) #結果 but エラー時例外(CalledProcessError)
  •      .Popen(cmd) #入出力時にファイル指定

cmd中身:引数を取る場合リストかタプルにする

  • cmd.strip().split(" ") なじみ深い処理。否応なくスペースがあれば区切る。
  • shlex.split(cmd) 文字列内に" "などの括りがある場合、その中のスペースで分けない。

"ls -l" --> ['ls', '-l']
"echo 'Hello world!'" --> ['echo', 'Hello world!'] #shlex.split(cmd)のみ

オプション

  • stdin:標準入力
  • stdout:標準出力
  • stderr:標準エラー出力
    • 下記の特殊値
    • 既存ファイル名、記述子 (正の整数)
    • None:リダイレクト無し
  • shell:シェル経由
    • sh -c "cmd"と同様
    • シェルインジェクションの危険性から非推奨。
    • シェルスクリプトに用いるような複雑なスクリプトの実行。
    • リストではなく文字列一本で入力(リストだと初めの要素がコマンド、以降は引数扱いとなる)。
    • *や~などの特殊な文字を機能させたい場合("ls *.txt"など)
    • パイプも可能
  • timeout:タイムアウト秒数

特殊値(Special value)

  • subprocess.DEVNULL:標準入出力先をos.devnull(ビットバケツ、ブラックホール)に指定
  • subprocess.PIPE:標準入出力先へのパイプ指定
  • subprocess.STDOUT:標準エラー出力が標準出力と同じハンドルに出力されるよう指定(2>1&。stderrに対してのみ)
エラー出力の統合
subprocess.check_output([cmd],stderr=subprocess.STDOUT)

subprocess.Popen.stdin/stdout/stderr

  • 返り値はopen()と同じ
  • 入力に対しては.write()や.close()などが使用可能。
  • 出力に対しては.read()や.close()などが使用可能。
パイプを通した出力の取得
subprocess.Popen(cmd, stdout=subprocess.PIPE,shell=True).stdout.readlines()

subprocess.Popen.communicate()

  • subprocess.Popen.stdout.read()、subprocess.Popen.stderr.read()でも出力を読むことができる。
  • が、出力サイズの制約を受けるなどで非推奨。
  • .communicate()に渡すと、(stdout_data, stderr_data)が受け取れる。
communicate()を用いた取得
subprocess.Popen([cmd], stdout=subprocess.PIPE).communicate()[0]
  • また、標準入力を与える際はcommunicate(input)の引数を指定する。
  • テキストファイルとして受け渡す場合、ファイルをopen()で開きread()で読取った形で与える。
communicate()を用いた入力1
subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate('Hello world!\n')[0]
communicate()を用いた入力2
subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate(open('input.txt','r').read())[0]
パイプでshellを使わない記述
p1 = subprocess.Popen([cmd1], stdout=subprocess.PIPE) #出力先にパイプ
p2 = subprocess.Popen([cmd2], stdin=p1.stdout, stdout=subprocess.PIPE) #入力にp1の受取
p1.stdout.close()
output = p2.communicate()[0] #stdout_data取得

その他オプションとデフォルト値

  • bufsize=-1:入出力の(ライン)バッファー設定。
  • executable=None:実行する置換プログラムの指定。
  • preexec_fn=None:子プロセス実行直前のファイル呼出。 #POSIX
  • close_fds=True:子プロセス実行前に 0, 1, 2 以外のファイル記述子を閉じる。 #POSIX
  • cwd=None:作業ディレクトリ
  • env=None:新プロセスでの環境変数を定義
  • universal_newlines=False:locale.getpreferredencoding() の代わりに locale.getpreferredencoding(False) を使用
  • startupinfo=None:基底の CreateProcess 関数に渡される STARTUPINFO #Windows
  • creationflags=0:CREATE_NEW_CONSOLE または CREATE_NEW_PROCESS_GROUP #Windows
  • restore_signals=True:SIG_IGN に設定したすべてのシグナルを子プロセスexec前にSIG_DFLに格納
  • start_new_session=False:サブプロセス実行前に子プロセス内で setsid() システムコール作成 #POSIX
  • pass_fds=():親と子の間で開いたままにしておくファイル記述子
  • encoding=None:標準入出力ファイルのエンコード名
  • errors=None:エンコード時のエラー処理
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away