Pythonのサブプロセスで出力をリダイレクトする方法は?


96

コマンドラインで私がすること:

cat file1 file2 file3 > myfile

私がPythonでやりたいこと:

import subprocess, shlex
my_cmd = 'cat file1 file2 file3 > myfile'
args = shlex.split(my_cmd)
subprocess.call(args) # spits the output in the window i call my python program

このようなコマンドをサブプロセスで実行しても、出力はありません。> myfilecat file1 file2 file3からの出力をpythonにリダイレクトせずに実行したいですか?
PoltoS、2011

@PoltoS一部のファイルを結合して、結果のファイルを処理したい。猫を使うのが一番簡単な方法だと思いました。それを行うためのより良い/ pythonicな方法はありますか?
catatemypythoncode

os.sendfile()ベースのソリューションが可能であり、参照pythonで、UNIXのcatコマンドに再現する
JFS

1
出力のリダイレクト( '>'または '>>')はサブプロセスでは機能しないと思います。Popen(少なくともPython 2.7では)(shell = Trueモード)この例では、他の人が指摘しているように、回避できますこれはリダイレクトを使用しないことによりますが、他の場合にはリダイレクトが役立ちます。サブプロセスでリダイレクトまたはパイピングがサポートされていない場合、Popenを文書化する必要があります(これが修正されるまで、os.system()は非推奨にしないでください)
Ribo

回答:


19

更新:os.systemは非推奨ですが、Python 3でも引き続き使用できます。


使用os.system

os.system(my_cmd)

あなたが本当にサブプロセスを使いたいのであれば、これが解決策です(ほとんどがサブプロセスのドキュメントから持ち上げられています):

p = subprocess.Popen(my_cmd, shell=True)
os.waitpid(p.pid, 0)

OTOH、システムコールを完全に回避できます:

import shutil

with open('myfile', 'w') as outfile:
    for infile in ('file1', 'file2', 'file3'):
        shutil.copyfileobj(open(infile), outfile)

1
それは機能しますが、次にあなたに尋ねさせてください:os.systemがすでに仕事を完了している場合、サブプロセスライブラリのポイントは何ですか?サブタスクはこのタスク専用のライブラリなので、代わりにサブプロセスを使用するべきだったと感じますが、今回は自分のためだけに使用しているので、今回はos.systemを使用します。
catatemypythoncode

サブプロセスライブラリはに比べてはるかに柔軟性が高くos.systemos.system正確にモデリングできますが、操作がより複雑になります。
Marcelo Cantos、2011

13
os.system前に来たsubprocess。前者は、後者が置き換える予定のレガシーAPIです。
サンタ

5
@catatemypythoncode:os.system()またはを使用しないでくださいshell=True。サブプロセスの出力をリダイレクトするには、Ryan Thompsonの回答にstdout示されているパラメーターを使用します。この場合、サブプロセス()は必要ありませんが、純粋なPythonを使用してファイルを連結できます。cat
jfs

4
大藤=一方
Cephlin

271

Python 3.5+出力をリダイレクトするだけのために開いているファイルハンドルを渡すstdout引数subprocess.run

# Use a list of args instead of a string
input_files = ['file1', 'file2', 'file3']
my_cmd = ['cat'] + input_files
with open('myfile', "w") as outfile:
    subprocess.run(my_cmd, stdout=outfile)

他の人が指摘したようにcat、この目的のような外部コマンドの使用は完全に無関係です。


9
これは、Pythonのシェルを使用する場合のパイピングの一般的な質問に対する答えになるはずです
Kaushik Ghose 14

46
これは正解であり、正解とマークされたものではありません。
Justin Blake

7
subprocess.run(my_cmd, stdout=outfile)置き換えられるPython 3.5+の使用subprocess.call(...)
Austin Yates

1
彼らはFILENOフィールドを持っていない場合注目すべきは、これは、カスタムファイルオブジェクトでは動作しません(彼らは実際のファイルでない場合。)
エリエゼルMiron氏

1
Python <3.5は現在サポートが終了しているため、コメント@AustinYatesで回答を更新しました。
Greg Dubicki

5

@PoltoS一部のファイルを結合して、結果のファイルを処理したい。猫を使うのが一番簡単な方法だと思いました。それを行うためのより良い/ pythonicな方法はありますか?

もちろん:

with open('myfile', 'w') as outfile:
    for infilename in ['file1', 'file2', 'file3']:
        with open(infilename) as infile:
            outfile.write(infile.read())

1
size = 'ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 dump.mp4 > file'
proc = subprocess.Popen(shlex.split(size), shell=True)
time.sleep(1)
proc.terminate() #proc.kill() modify it by a suggestion
size = ""
with open('file', 'r') as infile:
    for line in infile.readlines():
        size += line.strip()

print(size)
os.remove('file')

サブプロセスを使用する場合、プロセスを強制終了する必要があります。これは例です。プロセスを強制終了しないと、ファイルは空になり、何も読み取ることができません。Windowsで実行できます。 Unixで実行します。


1
それは(それがUnix上では動作しません。それは悪いプラクティスを示して悪いのコード例でfor line in .readlines():s +=)とproc.kill())一般的な情報の損失につながる可能性(それはサブプロセスは、Unix上で(正常に終了することはできません- unflushed内容が失われます)。とにかく、バッファリングに関するメモはコメントとしてより適切です。
jfs

私はWindowsで実行しても問題ありません(Windowsでkillを終了するのと同じだからです)Unixでは、proc.terminate()を使用する必要があります。@ JF Sebastian私のコンピュータにはUnixシステムがありません。
wyx

Windowsを使用している場合は、drop shlex.split()、drop shell=True、drop >file、drop open()などを使用stdout=PIPETimer(1, proc.terminate).start()ます。output = proc.communicate()[0]代わりに。ここだ完全な例。その他の解決策:ハングせずにPythonでプロセス出力の読み取りを停止しますか?注:質問には、子プロセスを手動で終了する必要があるという要件はありません。たとえば、stdoutがttyであるがトピックから外れている場合、プロセスの動作が異なるなど、他の問題に対処できます。
jfs

0

興味深いケースの1つは、同様のファイルを追加してファイルを更新することです。その後、プロセスで新しいファイルを作成する必要はありません。大きなファイルを追加する必要がある場合に特に役立ちます。pythonから直接teminalコマンドラインを使用する1つの可能性があります。

import subprocess32 as sub

with open("A.csv","a") as f:
    f.flush()
    sub.Popen(["cat","temp.csv"],stdout=f)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.