Menyimpan output dari subproses. Buka panggilan dalam sebuah string

300

Saya mencoba membuat panggilan sistem dengan Python dan menyimpan output ke string yang dapat saya manipulasi dalam program Python.

#!/usr/bin/python
import subprocess
p2 = subprocess.Popen("ntpq -p")

Saya sudah mencoba beberapa hal termasuk beberapa saran di sini:

Mengambil output dari subprocess.call ()

tetapi tanpa keberuntungan.

Menandai
sumber
3
Adalah baik untuk selalu memposting kode aktual yang Anda jalankan dan traceback aktual atau bahaviour yang tidak terduga untuk pertanyaan konkret seperti ini. Misalnya, saya tidak tahu apa yang Anda coba lakukan untuk mendapatkan output dan saya kira Anda tidak benar-benar memulai sejauh itu - Anda akan mendapatkan kesalahan tentang tidak menemukan file untuk "ntpq -p", yang merupakan bagian yang berbeda dari masalahnya daripada yang Anda tanyakan.
Mike Graham

Jawaban:

467

Dalam Python 2.7 atau Python 3

Alih-alih membuat Popenobjek secara langsung, Anda dapat menggunakan subprocess.check_output()fungsi untuk menyimpan output dari sebuah perintah dalam sebuah string:

from subprocess import check_output
out = check_output(["ntpq", "-p"])

Dalam Python 2.4-2.6

Gunakan communicatemetodenya.

import subprocess
p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE)
out, err = p.communicate()

out adalah apa yang kamu inginkan.

Catatan penting tentang jawaban lain

Perhatikan bagaimana saya menyampaikan perintah. The "ntpq -p"contoh memunculkan masalah lain. Karena Popentidak mengaktifkan shell, Anda akan menggunakan daftar perintah dan opsi— ["ntpq", "-p"].

Mike Graham
sumber
3
Dalam hal ini, apakah python menunggu panggilan sistem ini selesai? Atau perlukah memanggil fungsi wait / waitpid secara eksplisit?
NoneType
7
@NoneType, Popen.communicatetidak kembali sampai proses berakhir.
Mike Graham
10
jika Anda ingin mendapatkan aliran kesalahan, tambahkan stderr:p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Timofey
82
Hati-hati, subprocess.check_output()mengembalikan bytesobjek, bukan a str. Jika semua yang ingin Anda lakukan adalah mencetak hasilnya, itu tidak akan membuat perbedaan. Tetapi jika Anda ingin menggunakan metode seperti myString.split("\n")pada hasilnya, Anda harus terlebih dahulu mendekode bytesobjek: subprocess.check_output(myParams).decode("utf-8")misalnya.
TanguyP
17
menambahkan universal_newlines=Truesebagai parameter membantu saya dalam Python 3 untuk mendapatkan objek string. Jika universal_newlines Benar, mereka dibuka dalam mode teks dengan penyandian standar. Jika tidak, mereka dibuka sebagai aliran biner.
Jonathan Komar
38

Ini berfungsi untuk saya untuk mengarahkan ulang stdout (stderr dapat ditangani dengan cara yang sama):

from subprocess import Popen, PIPE
pipe = Popen(path, stdout=PIPE)
text = pipe.communicate()[0]

Jika tidak berhasil untuk Anda, sebutkan persis masalah yang Anda alami.

Eli Bendersky
sumber
3
Ini memang menghasilkan beberapa objek aneh. Ketika saya mengonversinya menjadi string, ia keluar seperti spasi \n.
Tomáš Zato - Reinstate Monica
1
Perhatikan bahwa ini tidak memeriksa apakah subproses berjalan dengan benar. Anda mungkin ingin memeriksa itu pipe.returncode == 0setelah baris terakhir juga.
thakis
alasan ini berhasil adalah karena Popenmengembalikan tuple dari stdoutdan stderr, jadi ketika Anda mengakses [0]Anda hanya meraih stdout. Anda juga bisa melakukannya text, err = pipe.communicate()dan textmendapatkan apa yang Anda harapkan
Jona
23

Dengan asumsi itu pwdhanya sebuah contoh, ini adalah bagaimana Anda dapat melakukannya:

import subprocess

p = subprocess.Popen("pwd", stdout=subprocess.PIPE)
result = p.communicate()[0]
print result

Lihat dokumentasi subproses untuk contoh lain dan informasi lebih lanjut.

Mark Byers
sumber
22

subprocess.Popen: http://docs.python.org/2/library/subprocess.html#subprocess.Popen

import subprocess

command = "ntpq -p"  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)

#Launch the shell command:
output = process.communicate()

print output[0]

Dalam konstruktor Popen, jika shell adalah Benar , Anda harus lulus perintah sebagai string bukan sebagai urutan. Jika tidak, cukup bagi perintah ke dalam daftar:

command = ["ntpq", "-p"]  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)

Jika Anda perlu membaca juga kesalahan standar, ke inisialisasi Popen, Anda dapat mengatur stderr ke subproses.PIPE atau ke subprocess.STDOUT :

import subprocess

command = "ntpq -p"  # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

#Launch the shell command:
output, error = process.communicate()
Paolo Rovelli
sumber
luar biasa inilah yang saya cari
kRazzy R
14

untuk Python 2.7+, jawaban idiomatis adalah menggunakan subprocess.check_output()

Anda juga harus mencatat penanganan argumen saat menjalankan subproses, karena dapat sedikit membingungkan ....

Jika args hanya perintah tunggal tanpa args sendiri (atau Anda telah shell=Truemengatur), itu bisa berupa string. Kalau tidak, itu harus daftar.

misalnya ... untuk menjalankan lsperintah, ini tidak masalah:

from subprocess import check_call
check_call('ls')

begitu juga ini:

from subprocess import check_call
check_call(['ls',])

namun, jika Anda ingin meneruskan beberapa argumen ke perintah shell, Anda tidak bisa melakukan ini:

from subprocess import check_call
check_call('ls -al')

alih-alih, Anda harus meneruskannya sebagai daftar:

from subprocess import check_call
check_call(['ls', '-al'])

yang shlex.split()fungsi kadang-kadang dapat berguna untuk membagi string menjadi shell-seperti sintaks sebelum membuat subproses ... seperti ini:

from subprocess import check_call
import shlex
check_call(shlex.split('ls -al'))
Corey Goldberg
sumber
Lima tahun kemudian, pertanyaan ini masih mendapatkan banyak cinta. Terima kasih untuk pembaruan 2.7+, Corey!
Mark
11

Ini bekerja dengan baik untuk saya:

import subprocess
try:
    #prints results and merges stdout and std
    result = subprocess.check_output("echo %USERNAME%", stderr=subprocess.STDOUT, shell=True)
    print result
    #causes error and merges stdout and stderr
    result = subprocess.check_output("copy testfds", stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError, ex: # error code <> 0 
    print "--------error------"
    print ex.cmd
    print ex.message
    print ex.returncode
    print ex.output # contains stdout and stderr together 
Patrick Wolf
sumber
9

Ini sempurna bagi saya. Anda akan mendapatkan kode pengembalian, stdout dan stderr dalam sebuah tuple.

from subprocess import Popen, PIPE

def console(cmd):
    p = Popen(cmd, shell=True, stdout=PIPE)
    out, err = p.communicate()
    return (p.returncode, out, err)

Sebagai contoh:

result = console('ls -l')
print 'returncode: %s' % result[0]
print 'output: %s' % result[1]
print 'error: %s' % result[2]
gravmatt
sumber
6

Jawaban yang diterima masih bagus, hanya beberapa komentar tentang fitur yang lebih baru. Karena python 3.6, Anda dapat menangani pengodean langsung di check_output, lihat dokumentasi . Ini mengembalikan objek string sekarang:

import subprocess 
out = subprocess.check_output(["ls", "-l"], encoding="utf-8")

Dalam python 3.7, parameter capture_outputditambahkan ke subprocess.run (), yang melakukan beberapa penanganan Popen / PIPE untuk kami, lihat dokumen python :

import subprocess 
p2 = subprocess.run(["ls", "-l"], capture_output=True, encoding="utf-8")
p2.stdout
ynux
sumber
4
 import os   
 list = os.popen('pwd').read()

Dalam hal ini Anda hanya akan memiliki satu elemen dalam daftar.

Alex
sumber
7
os.popensudah usang karena subprocessmodul.
Mike Graham
3
Ini cukup membantu untuk admin di kotak lama menggunakan seri 2.2.X dari Python.
Neil McF
4

Saya menulis sedikit fungsi berdasarkan jawaban lain di sini:

def pexec(*args):
    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0].rstrip()

Pemakaian:

changeset = pexec('hg','id','--id')
branch = pexec('hg','id','--branch')
revnum = pexec('hg','id','--num')
print('%s : %s (%s)' % (revnum, changeset, branch))
Mpen
sumber
4

Dalam Python 3.7 argumen kata kunci baru capture_outputdiperkenalkan untuk subprocess.run. Mengaktifkan pendek dan sederhana:

import subprocess

p = subprocess.run("echo 'hello world!'", capture_output=True, shell=True, encoding="utf8")
assert p.stdout == 'hello world!\n'
erb
sumber
1
import subprocess
output = str(subprocess.Popen("ntpq -p",shell = True,stdout = subprocess.PIPE, 
stderr = subprocess.STDOUT).communicate()[0])

Ini adalah solusi satu baris

Kirti Kedia
sumber
0

Berikut ini menangkap stdout dan stderr proses dalam satu variabel. Ini kompatibel dengan Python 2 dan 3:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

Jika perintah Anda adalah string daripada array, awali ini dengan:

import shlex
command = shlex.split(command)
Zags
sumber
0

Untuk python 3.5 saya memasang fungsi berdasarkan jawaban sebelumnya. Log dapat dihapus, pikir itu bagus untuk dimiliki

import shlex
from subprocess import check_output, CalledProcessError, STDOUT


def cmdline(command):
    log("cmdline:{}".format(command))
    cmdArr = shlex.split(command)
    try:
        output = check_output(cmdArr,  stderr=STDOUT).decode()
        log("Success:{}".format(output))
    except (CalledProcessError) as e:
        output = e.output.decode()
        log("Fail:{}".format(output))
    except (Exception) as e:
        output = str(e);
        log("Fail:{}".format(e))
    return str(output)


def log(msg):
    msg = str(msg)
    d_date = datetime.datetime.now()
    now = str(d_date.strftime("%Y-%m-%d %H:%M:%S"))
    print(now + " " + msg)
    if ("LOG_FILE" in globals()):
        with open(LOG_FILE, "a") as myfile:
            myfile.write(now + " " + msg + "\n")
Pavel Niedoba
sumber
0

Gunakan ckeck_outputmetodesubprocess

import subprocess
address = 192.168.x.x
res = subprocess.check_output(['ping', address, '-c', '3'])

Akhirnya parsing string

for line in res.splitlines():

Semoga bisa membantu, selamat coding

Salman Mushtaq
sumber