Jika saya melakukan hal berikut:
import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
Saya mendapat:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__
(p2cread, p2cwrite,
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles
p2cread = stdin.fileno()
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'
Rupanya objek cStringIO.StringIO tidak berdetak cukup dekat ke file bebek yang sesuai dengan subprocess.Popen. Bagaimana saya mengatasi ini?
python
subprocess
stdin
Daryl Spitzer
sumber
sumber
call(['ls', '-1'], shell=True)
salah. Saya sarankan untuk membaca pertanyaan umum dari deskripsi tag subproses sebagai gantinya. Secara khusus, Mengapa subprocess.Popen tidak berfungsi ketika args adalah urutan? menjelaskan mengapacall(['ls', '-1'], shell=True)
itu salah. Saya ingat meninggalkan komentar di bawah posting blog tetapi saya tidak melihatnya sekarang karena beberapa alasan.subprocess.run
lihat stackoverflow.com/questions/48752152/…Jawaban:
Popen.communicate()
dokumentasi:Jadi contoh Anda dapat ditulis sebagai berikut:
Pada versi Python 3 saat ini, Anda bisa menggunakan
subprocess.run
, untuk meneruskan input sebagai string ke perintah eksternal dan mendapatkan status keluarnya, dan hasilnya sebagai string kembali dalam satu panggilan:sumber
Saya menemukan solusi ini:
Apakah ada yang lebih baik?
sumber
stdin.write()
penggunaan tidak disarankan,p.communicate()
harus digunakan. Lihat jawaban saya.communicate
akan menutup pipa dan membiarkan proses berakhir dengan anggun.read()
dari itu, seperticommunicate()
halnya bahkan tanpa argumen).Saya agak terkejut tidak ada yang menyarankan membuat pipa, yang menurut saya cara paling sederhana untuk meneruskan string ke stdin dari subproses:
sumber
os
dansubprocess
dokumentasi berdua sepakat bahwa Anda harus memilih yang terakhir atas mantan. Ini adalah solusi lama yang memiliki penggantian standar (sedikit kurang ringkas); jawaban yang diterima mengutip dokumentasi terkait.Ada solusi yang bagus jika Anda menggunakan Python 3.4 atau lebih baik. Gunakan
input
argumen alih-alihstdin
argumen, yang menerima argumen byte:Ini bekerja untuk
check_output
danrun
, tetapi tidakcall
ataucheck_call
untuk beberapa alasan.sumber
check_output
harusinput
berdebat, tetapi tidakcall
.check_call
tetapi bekerja untukrun
. Ini juga bekerja dengan input = string selama Anda melewati argumen encoding juga sesuai dengan dokumentasi.Saya menggunakan python3 dan menemukan bahwa Anda perlu menyandikan string Anda sebelum Anda dapat meneruskannya ke stdin:
sumber
b'something'
). Ini akan mengembalikan err dan out sebagai byte juga. Jika Anda ingin menghindari ini, Anda bisa meneruskanuniversal_newlines=True
kePopen
. Maka ia akan menerima input sebagai str dan akan mengembalikan err / out sebagai str juga.universal_newlines=True
juga akan mengonversi baris baru Anda agar sesuai dengan sistem AndaAku takut tidak. Pipa adalah konsep OS tingkat rendah, sehingga benar-benar membutuhkan objek file yang diwakili oleh deskriptor file tingkat OS. Solusi Anda adalah yang benar.
sumber
sumber
Berhati-hatilah yang
Popen.communicate(input=s)
mungkin memberi Anda masalah jikas
terlalu besar, karena tampaknya proses induk akan buffer sebelum forking subproses anak, yang berarti perlu "digunakan memori" dua kali lebih banyak pada saat itu (setidaknya sesuai dengan penjelasan "di bawah tenda" dan dokumentasi terkait ditemukan di sini ). Dalam kasus khusus saya,s
adalah generator yang pertama kali sepenuhnya diperluas dan baru kemudian ditulis untukstdin
sehingga proses induk sangat besar sebelum anak itu lahir, dan tidak ada memori yang tersisa untuk memotongnya:File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory
sumber
sumber
shell=True
begitu umum digunakan tanpa alasan yang baik, dan ini adalah pertanyaan yang populer, izinkan saya menunjukkan bahwa ada banyak situasi di manaPopen(['cmd', 'with', 'args'])
jelas lebih baik daripadaPopen('cmd with args', shell=True)
dan memiliki shell memecah perintah dan argumen menjadi token, tetapi tidak sebaliknya memberikan apa pun berguna, sambil menambahkan sejumlah kompleksitas dan dengan demikian juga menyerang permukaan.sumber
Pada Python 3.7+ lakukan ini:
dan Anda mungkin ingin menambahkan
capture_output=True
untuk mendapatkan output dari menjalankan perintah sebagai string.Pada versi Python yang lebih lama, ganti
text=True
denganuniversal_newlines=True
:sumber