Bagaimana cara mengarahkan keluaran dengan subproses dengan Python?

97

Apa yang saya lakukan di baris perintah:

cat file1 file2 file3 > myfile

Yang ingin saya lakukan dengan 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
catatemypythoncode.dll
sumber
Menjalankan perintah seperti itu dalam subproses tidak akan memberi Anda keluaran apa pun. Mungkin Anda ingin menjalankannya tanpa > myfile mengalihkan output dari cat file1 file2 file3 ke python?
PoltoS
@PoltoS Saya ingin menggabungkan beberapa file dan kemudian memproses file yang dihasilkan. Saya pikir menggunakan kucing adalah alternatif yang paling mudah. Apakah ada cara yang lebih baik / pythonic untuk melakukannya?
catatemypythoncode
os.sendfile()solusi berbasis mungkin, lihat Mereproduksi perintah unix cat di python
jfs
1
Saya pikir pengalihan keluaran ('>' atau '>>') tidak berfungsi dalam subproses. Buka (setidaknya dengan Python 2.7) (dalam shell = mode True) Dalam contoh ini, seperti yang ditunjukkan orang lain, Anda dapat mengatasinya ini dengan tidak menggunakan pengalihan, tetapi dalam kasus lain pengalihan berguna. Jika pengalihan atau perpipaan tidak didukung dalam subproses. Terbuka harus didokumentasikan (dan / atau os.system () tidak boleh ditinggalkan sampai ini diperbaiki)
Ribo

Jawaban:

20

UPDATE: os.system tidak disarankan, meskipun masih tersedia dengan Python 3.


Penggunaan os.system:

os.system(my_cmd)

Jika Anda benar-benar ingin menggunakan subproses, berikut solusinya (sebagian besar diangkat dari dokumentasi untuk subproses):

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

OTOH, Anda dapat menghindari panggilan sistem sepenuhnya:

import shutil

with open('myfile', 'w') as outfile:
    for infile in ('file1', 'file2', 'file3'):
        shutil.copyfileobj(open(infile), outfile)
Marcelo Cantos
sumber
1
Ini berfungsi, tetapi izinkan saya bertanya kepada Anda: Apa gunanya perpustakaan subproses jika os.system sudah menyelesaikan pekerjaan? Saya merasa saya seharusnya menggunakan subproses sebagai gantinya karena ini adalah perpustakaan yang didedikasikan untuk tugas ini, meskipun karena saya melakukan ini hanya untuk diri saya sendiri, saya akan baik-baik saja menggunakan os.system kali ini.
catatemypythoncode
Pustaka subproses jauh lebih fleksibel daripada os.system, dan dapat membuat model dengan os.systemtepat, tetapi juga lebih kompleks untuk dikerjakan.
Marcelo Cantos
13
os.systemdatang sebelumnya subprocess. Yang pertama adalah API lama yang ingin diganti oleh yang terakhir.
Santa
5
@catatemypythoncode: Anda tidak boleh menggunakan os.system()atau shell=True. Untuk mengarahkan keluaran subproses, gunakan stdoutparameter seperti yang ditunjukkan dalam jawaban Ryan Thompson . Meskipun Anda tidak memerlukan subprocess ( cat) dalam kasus Anda, Anda dapat menggabungkan file menggunakan Python murni.
jfs
4
OTOH = Sebaliknya
Cephlin
272

Di Python 3.5+ untuk mengalihkan keluaran, cukup berikan pegangan file terbuka untuk stdoutargumen ke 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)

Seperti yang ditunjukkan orang lain, penggunaan perintah eksternal seperti catuntuk tujuan ini sama sekali tidak relevan.

Ryan C. Thompson
sumber
9
Ini seharusnya menjadi jawaban untuk pertanyaan umum tentang perpipaan saat menggunakan shell dari Python
Kaushik Ghose
47
Ini adalah jawaban yang benar, bukan yang ditandai sebagai benar.
Justin Blake
7
Untuk penggunaan Python 3.5+ subprocess.run(my_cmd, stdout=outfile)yang menggantikansubprocess.call(...)
Austin Yates
1
Catatan, ini tidak bekerja dengan objek file kustom, jika mereka tidak memiliki bidang fileno (jika mereka bukan file nyata.)
Eliezer Miron
1
Karena Python <3.5 sudah tidak digunakan lagi, saya telah memperbarui jawabannya dengan komentar Anda, @AustinYates.
Greg Dubicki
5

@PoltoS Saya ingin menggabungkan beberapa file dan kemudian memproses file yang dihasilkan. Saya pikir menggunakan kucing adalah alternatif yang paling mudah. Apakah ada cara yang lebih baik / pythonic untuk melakukannya?

Tentu saja:

with open('myfile', 'w') as outfile:
    for infilename in ['file1', 'file2', 'file3']:
        with open(infilename) as infile:
            outfile.write(infile.read())
SingleNegationElimination
sumber
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')

Ketika Anda menggunakan subproses , proses harus dimatikan. Ini adalah contoh. Jika Anda tidak menghentikan proses, file akan kosong dan Anda tidak dapat membaca apa-apa, dapat berjalan di Windows. Saya tidak dapat memastikan bahwa itu bisa dijalankan di Unix.

wyx
sumber
1
Ini adalah contoh kode yang buruk (tidak akan berfungsi di Unix; ini menunjukkan praktik yang buruk for line in .readlines():, s +=) dan proc.kill()dapat menyebabkan hilangnya informasi secara umum (tidak memungkinkan subproses untuk dihentikan dengan baik (di Unix) - konten yang tidak dibilas akan hilang ). Bagaimanapun, catatan tentang buffering lebih cocok sebagai komentar.
jfs
Saya menjalankannya di Windows tidak apa-apa (Karena membunuh sama dengan menghentikan di Windows). Di Unix mungkin Anda harus menggunakan proc.terminate (). @ JF Sebastian Saya belum memiliki Sistem Unix di komputer saya.
wyx
Jika Anda berada di Windows kemudian turun shlex.split(), penurunan shell=True, penurunan >file, penurunan open(), dll dan penggunaan stdout=PIPE, Timer(1, proc.terminate).start(); output = proc.communicate()[0]sebagai gantinya. Berikut contoh lengkapnya . Solusi lainnya: Hentikan membaca keluaran proses dengan Python tanpa hang? Catatan: tidak ada persyaratan dalam pertanyaan bahwa Anda perlu menghentikan proses anak secara manual - Anda dapat mengatasi masalah lain misalnya, suatu proses mungkin berperilaku berbeda jika stdout-nya tty tetapi di luar topik.
jfs
0

Salah satu kasus yang menarik adalah memperbarui file dengan menambahkan file serupa ke dalamnya. Maka seseorang tidak perlu membuat file baru dalam prosesnya. Ini sangat berguna dalam kasus di mana file besar perlu ditambahkan. Berikut adalah salah satu kemungkinan menggunakan baris perintah teminal langsung dari python.

import subprocess32 as sub

with open("A.csv","a") as f:
    f.flush()
    sub.Popen(["cat","temp.csv"],stdout=f)
DJJ
sumber