Cara menggunakan perintah `subprocess` dengan pipa

246

Saya ingin menggunakan subprocess.check_output()dengan ps -A | grep 'process_name'. Saya mencoba berbagai solusi tetapi sejauh ini tidak ada yang berhasil. Bisakah seseorang membimbing saya bagaimana melakukannya?

zuberuber
sumber
4
ada psutilyang memungkinkan untuk mendapatkan info proses secara portabel.
jfs

Jawaban:

438

Untuk menggunakan pipa dengan subprocessmodul, Anda harus lulus shell=True.

Namun, ini tidak benar-benar disarankan karena berbagai alasan, paling tidak keamanannya. Alih-alih, buat psdan grepproses secara terpisah, dan pipa keluaran dari satu ke yang lain, seperti:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

Namun, dalam kasus khusus Anda, solusi sederhana adalah menelepon subprocess.check_output(('ps', '-A'))dan kemudian str.findpada output.

Taymon
sumber
81
+1 untuk memisahkan output / input untuk menghindari penggunaanshell=True
Nicolas
5
Jangan lupa, kesalahan subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1hanya berarti bahwa tidak ada yang ditemukan oleh grep, jadi itu perilaku normal.
Serge
2
Mengapa kita membutuhkannya ps.wait()ketika kita sudah memiliki output. ps.wait.__doc__menunggu anak untuk berakhir tetapi konten anak tampaknya sudah dimasukkan ke dalam outputvariabel
Papouche Guinslyzinho
3
@MakisH Anda sedang melihat string.find, yang telah usang dalam mendukung str.find(yaitu, metode findpada strobjek).
Taymon
4
Catatan: jika grepmati sebelum waktunya; psdapat menggantung tanpa batas waktu jika menghasilkan output yang cukup untuk mengisi buffer pipa OS-nya (karena Anda belum memanggil ps.stdout.close()induknya). Tukar urutan awal, untuk menghindarinya
jfs
54

Atau Anda selalu dapat menggunakan metode komunikasi pada objek subproses.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

Metode berkomunikasi mengembalikan tupel dari output standar dan kesalahan standar.

jkalivas
sumber
3
Saya pikir menggunakan communicatelebih baik daripada wait. Ada peringatan seperti itu: "Ini akan menemui jalan buntu ketika menggunakan stdout = PIPE dan / atau stderr = PIPE dan proses anak menghasilkan output yang cukup untuk pipa sehingga memblokir menunggu buffer pipa OS untuk menerima lebih banyak data. Gunakan berkomunikasi () untuk hindari itu. "
Paolo
2
Untuk memperjelas komentar Paolo di atas, peringatannya adalah untuk menunggu, bukan untuk berkomunikasi - yaitu alasan ia mengatakan komunikasi lebih baik.
EnemyBagJones
23

Lihat dokumentasi tentang menyiapkan saluran pipa menggunakan subproses: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Saya belum menguji contoh kode berikut tetapi seharusnya kira-kira seperti yang Anda inginkan:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
AlcubierreDrive
sumber
2
Setelah memeriksa ini gagal, lihat jawaban di bawah oleh Taymon untuk sesuatu yang bekerja tanpa mucking sekitar
Alvin
2
subprocess.check_output tampaknya tidak ada di Python 2.6.9
RightmireM
6

Solusi JKALAVIS baik, namun saya akan menambahkan peningkatan untuk menggunakan shlex bukan SHELL = TRUE. di bawah ini saya mencantumkan waktu kueri

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
Daniel Smith
sumber
1
Kenapa shellx over shell?
AFP_555
2
di mana shlex digunakan di sini?
3lokh
4

Juga, coba gunakan 'pgrep'perintah, bukan'ps -A | grep 'process_name'

Shooe
sumber
2
jika Anda ingin mendapatkan proses id, jelas
Shooe
3

Anda dapat mencoba fungsi pipa di sh.py :

import sh
print sh.grep(sh.ps("-ax"), "process_name")
amoffat
sumber
0

Setelah Python 3.5 Anda juga dapat menggunakan:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

Eksekusi dari perintah ini sedang diblokir dan output akan berada di process.stdout .

zingi
sumber