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.


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"].


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.


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.


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()

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'))

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 

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]

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

4
 import os   
 list = os.popen('pwd').read()

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


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))

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'

1
import subprocess
output = str(subprocess.Popen("ntpq -p",shell = True,stdout = subprocess.PIPE, 
stderr = subprocess.STDOUT).communicate()[0])

Ini adalah solusi satu baris


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)

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")

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.