Saya mencoba menulis skrip wrapper untuk program baris perintah (svnadmin memverifikasi) yang akan menampilkan indikator kemajuan yang bagus untuk operasi. Ini mengharuskan saya untuk dapat melihat setiap baris output dari program yang dibungkus segera setelah itu adalah output.
Saya pikir saya hanya akan menjalankan program menggunakan subprocess.Popen
, menggunakan stdout=PIPE
, kemudian membaca setiap baris ketika masuk dan bertindak sesuai. Namun, ketika saya menjalankan kode berikut, output tampaknya buffer di suatu tempat, menyebabkannya muncul dalam dua potongan, baris 1 hingga 332, kemudian 333 hingga 439 (baris terakhir output)
from subprocess import Popen, PIPE, STDOUT
p = Popen('svnadmin verify /var/svn/repos/config', stdout = PIPE,
stderr = STDOUT, shell = True)
for line in p.stdout:
print line.replace('\n', '')
Setelah melihat dokumentasi pada subproses sedikit, saya menemukan bufsize
parameter untuk Popen
, jadi saya mencoba menetapkan bufsize ke 1 (buffer setiap baris) dan 0 (tidak ada buffer), tetapi tidak ada nilai yang tampaknya mengubah cara jalur dikirim.
Pada titik ini saya mulai memahami sedotan, jadi saya menulis loop keluaran berikut:
while True:
try:
print p.stdout.next().replace('\n', '')
except StopIteration:
break
tetapi mendapat hasil yang sama.
Apakah mungkin untuk mendapatkan output program 'realtime' dari suatu program yang dieksekusi menggunakan subproses? Apakah ada opsi lain di Python yang kompatibel dengan maju (tidak exec*
)?
sumber
sydout=PIPE
sehingga proses menulis langsung ke konsol Anda, melewati proses induk?Jawaban:
Saya mencoba ini, dan untuk beberapa alasan sementara kode
buffer secara agresif, varian
tidak. Rupanya ini adalah bug yang dikenal: http://bugs.python.org/issue3907 (Masalahnya sekarang "Ditutup" pada 29 Agustus 2018)
sumber
while p.poll() is None
alih-alihwhile True
, dan menghapusif not line
print(line.decode('utf-8').rstrip())
.PYTHONUNBUFFERED=1
. Ini sangat berguna untuk keluaran yang tidak terbatassumber
p.stdout.close()
tidak jelas.Anda dapat mengarahkan output subproses ke stream secara langsung. Contoh sederhana:
sumber
.communicate()
? Atau konten hilang ke induk stderr / stdout stream?communicate()
metode untuk kembaliCompletedProcess
. Juga,capture_output
saling eksklusif denganstdout
danstderr
.Anda dapat mencoba ini:
Jika Anda menggunakan readline sebagai ganti read, akan ada beberapa kasus di mana pesan input tidak dicetak. Cobalah dengan perintah yang memerlukan input inline dan lihat sendiri.
sumber
The Streaming subproses stdin dan stdout dengan asyncio di Python posting blog oleh Kevin McCarthy menunjukkan bagaimana melakukannya dengan asyncio:
sumber
import nest_asyncio; nest_asyncio.apply()
dan menggunakan perintah shell, yaituprocess = await create_subprocess_shell(*command, stdout=PIPE, stderr=PIPE, shell=True)
alih-alihprocess = await create_subprocess_exec(...)
. Bersulang!Masalah Output Real Time diselesaikan: Saya memang mengalami masalah serupa di Python, sambil menangkap output real time dari program c. Saya menambahkan " fflush (stdout) ;" dalam kode C saya. Ini berhasil untuk saya. Ini adalah snip kodenya
<< Program C >>
<< Program Python >>
<< OUTPUT >> Cetak: Hitungan 1 Cetak: Hitungan 2 Cetak: Hitungan 3
Semoga ini bisa membantu.
~ sairam
sumber
flush(stdout)
) di C ++. Terima kasih!Saya mengalami masalah yang sama beberapa waktu lalu. Solusi saya adalah membuang iterasi untuk
read
metode ini, yang akan segera kembali walaupun subproses Anda belum selesai dieksekusi, dll.sumber
Tergantung pada kasus penggunaan, Anda mungkin juga ingin menonaktifkan buffering dalam subproses itu sendiri.
Jika subproses akan menjadi proses Python, Anda bisa melakukan ini sebelum panggilan:
Atau sebagai alternatif, berikan
env
argumen ini padaPopen
.Jika tidak, jika Anda menggunakan Linux / Unix, Anda dapat menggunakan
stdbuf
alat ini. Misalnya suka:Lihat juga di sini tentang
stdbuf
atau opsi lain.(Lihat juga di sini untuk jawaban yang sama.)
sumber
Saya menggunakan solusi ini untuk mendapatkan output realtime pada suatu subproses. Loop ini akan berhenti segera setelah proses selesai tanpa meninggalkan kebutuhan untuk pernyataan break atau loop tak terbatas yang mungkin.
sumber
if out=='': break
setelahout = sub_process...
Menemukan fungsi "plug-and-play" ini di sini . Bekerja seperti pesona!
sumber
stderr=subprocess.STDOUT
sebenarnya sangat membantu dalam menangkap data streaming. Saya membatalkannya.Anda dapat menggunakan iterator pada setiap byte dalam output dari subproses. Ini memungkinkan pembaruan inline (baris yang diakhiri dengan '\ r' menimpa jalur output sebelumnya) dari subproses:
sumber
Dalam Python 3.x proses mungkin hang karena outputnya adalah array byte, bukan string. Pastikan Anda mendekodekannya menjadi string.
Mulai dari Python 3.6 Anda bisa melakukannya menggunakan parameter
encoding
di Popen Constructor . Contoh lengkap:Perhatikan bahwa kode ini mengalihkan
stderr
kestdout
dan menangani kesalahan output .sumber
Menggunakan pexpect [ http://www.noah.org/wiki/Pexpect ] dengan readlines non-blocking akan menyelesaikan masalah ini. Ini berasal dari fakta bahwa pipa di-buffer, dan output aplikasi Anda semakin di-buffer oleh pipa, oleh karena itu Anda tidak bisa mencapai output itu sampai buffer mengisi atau proses mati.
sumber
Solusi lengkap:
sumber
universal_newlines=True
padaPopen()
panggilan, Anda mungkin tidak perlu untuk menempatkan penanganan Anda sendiri dari mereka dalam, juga - itulah inti dari pilihan.Ini adalah kerangka dasar yang selalu saya gunakan untuk ini. Ini membuatnya mudah untuk menerapkan batas waktu dan mampu menangani proses gantung yang tidak terhindarkan.
sumber
(Solusi ini telah diuji dengan Python 2.7.15)
Anda hanya perlu sys.stdout.flush () setelah setiap baris membaca / menulis:
sumber
Beberapa jawaban menyarankan python 3.x atau pthon 2.x, kode di bawah ini akan berfungsi untuk keduanya.
sumber