Bir alt dizede çağrıyı aç


301

Python bir sistem çağrısı yapmak ve Python programında manipüle edebilir bir dizeye çıktı depolamak çalışıyorum.

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

Buradaki bazı önerileri içeren birkaç şeyi denedim:

Subprocess.call () çıktısını alma

ama şanssız.


3
Çalıştırdığınız gerçek kodu ve bunun gibi somut sorular için gerçek geri izleme veya beklenmedik davranışları yayınlamak her zaman iyidir. Örneğin, çıktıyı almak için ne yapmaya çalıştığınızı bilmiyorum ve aslında bu kadar başlangıç ​​yapamadığınızdan şüpheliyim - dosyayı bulma konusunda bir hata alırsınız "ntpq -p", ki bu sormaktan çok sorun.
Mike Graham

Yanıtlar:


468

Python 2.7 veya Python 3'te

Bir Popennesneyi doğrudan yapmak yerine, bir komutun çıktısını bir dizede saklamak için subprocess.check_output()işlevi kullanabilirsiniz :

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

Python 2.4-2.6'da

communicateYöntemi kullanın .

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

out istediğin şey bu.

Diğer cevaplar hakkında önemli not

Komutta nasıl geçtiğime dikkat edin. "ntpq -p"Örnek başka konuyu gündeme getiriyor. Yana Popenkabuk çağırmak değil, komut ve seçenekleri-bir listesini kullanmak istiyorsunuz ["ntpq", "-p"].


3
Bu durumda, python bu sistem çağrısının bitmesini bekliyor mu? Yoksa wait / waitpid işlevini açıkça çağırmak gerekli mi?
NoneType

7
@NoneType, Popen.communicateişlem sonlanıncaya kadar geri dönmez.
Mike Graham

10
hata akışı almak istiyorsanız stderr ekleyin:p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Timofey

82
Dikkatli ol, nesneyi subprocess.check_output()döndürür, a bytesdeğil str. Tek yapmanız gereken sonucu yazdırmak, herhangi bir fark yaratmaz. Ancak myString.split("\n")sonuç gibi bir yöntem kullanmak istiyorsanız , önce bytesnesnenin kodunu çözmeniz gerekir : subprocess.check_output(myParams).decode("utf-8")örneğin.
TanguyP

17
universal_newlines=Trueparametre olarak eklemek , Python 3'te dize nesnesini almama yardımcı oldu. Universal_newlines True ise, varsayılan kodlamayla metin modunda açılırlar. Aksi takdirde, ikili akışlar olarak açılırlar.
Jonathan Komar

38

Bu stdout yönlendirmek için benim için çalıştı (stderr benzer şekilde ele alınabilir):

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

İşinize yaramazsa, lütfen yaşadığınız sorunu tam olarak belirtin.


4
Bu bazı tuhaf nesneler üretir. Ben dize dönüştürdüğümde, boşluk gibi kaçar \n.
Tomáš Zato - Monica'yı

1
Bunun, alt işlemin doğru çalışıp çalışmadığını kontrol etmediğini unutmayın. Muhtemelen pipe.returncode == 0son satırdan sonra da kontrol etmek istersiniz .
thakis

Bunun nedeni, Popenbir demet döndürmesi stdoutve stderrböylece eriştiğinizde [0]sadece kapma stdout. Ayrıca yapabilir text, err = pipe.communicate()ve textbeklediğiniz gibi olacak
Jona

23

Bunun pwdsadece bir örnek olduğunu varsayarsak , bunu şu şekilde yapabilirsiniz:

import subprocess

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

Başka bir örnek ve daha fazla bilgi için alt işlem belgelerine bakın .


22

Açma: 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]

Eğer POPEN Yapıcıda, kabuk olan Doğru , bir dize olarak yerine dizi olarak komutu geçmelidir. Aksi takdirde, komutu bir listeye bölün:

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

Popen başlatma içine, aynı zamanda standart hatayı okumak gerekiyorsa, ayarlayabilirsiniz stderr'yi için subprocess.PIPE veya 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()

müthiş bu aradığım şey
kRazzy R

15

Python 2.7+ için deyimsel cevap kullanmak subprocess.check_output()

Ayrıca, bir alt süreci başlatırken, biraz kafa karıştırıcı olabileceği için argümanların işlenmesine de dikkat etmelisiniz.

Bağımsız değişkenler yalnızca kendi bağımsız değişkenleri olmayan tek bir komutsa (veya shell=Trueayarladıysanız), bir dize olabilir. Aksi takdirde bir liste olmalıdır.

örneğin ... lskomutu çağırmak için sorun değil:

from subprocess import check_call
check_call('ls')

Öyleyse bu:

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

ancak, kabuk komutuna bazı argümanlar iletmek istiyorsanız, bunu yapamazsınız :

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

bunun yerine bir liste olarak iletmeniz gerekir:

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

shlex.split()fonksiyon bazen benzeri kabuk sözdizimi böyle ... Bir subprocesses oluşturmadan önce içine bir dize bölmek yararlı olabilir:

from subprocess import check_call
import shlex
check_call(shlex.split('ls -al'))

Beş yıl sonra, bu soru hala çok seviliyor. 2.7+ güncelleme için teşekkürler Corey!
Mark

11

Bu benim için mükemmel çalışıyor:

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

Bu benim için mükemmeldi. Bir tuple içinde dönüş kodu, stdout ve stderr alacaksınız.

from subprocess import Popen, PIPE

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

Örneğin:

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

6

Kabul edilen cevap hala iyidir, yeni özellikler hakkında birkaç açıklama. Python 3.6 olduğundan, kodlamayı doğrudan işleyebilirsiniz check_output, belgelere bakın . Bu, şimdi bir dize nesnesi döndürür:

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

Python capture_output3.7'de, bizim için bazı Popen / PIPE işlemlerini yapan subprocess.run () öğesine bir parametre eklendi , python belgelerine bakın :

import subprocess 
p2 = subprocess.run(["ls", "-l"], capture_output=True, encoding="utf-8")
p2.stdout

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

Bu durumda listede yalnızca bir öğe olacaktır.


7
os.popensubprocessmodül lehine kullanımdan kaldırılmıştır .
Mike Graham

3
Bu, Python'un 2.2.X serisini kullanan eski bir kutudaki yönetici için oldukça yararlı oldu.
Neil McF

4

Buradaki diğer cevaplara dayanarak küçük bir fonksiyon yazdım:

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

Kullanımı:

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

4

Python 3.7'de yeni bir anahtar kelime argümanı capture_outputtanıtıldı subprocess.run. Kısa ve basit özelliklerin etkinleştirilmesi:

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

Bu tek satırlık bir çözüm


0

Aşağıdaki, işlemin stdout ve stderr'ını tek bir değişkende yakalar. Python 2 ve 3 uyumludur:

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

Komutunuz bir dizi yerine bir dize ise, bu kodun başına şunu ekleyin:

import shlex
command = shlex.split(command)

0

Python 3.5 için önceki cevaba dayanarak fonksiyon koydum. Günlük kaldırılabilir, olması güzel olduğunu düşündüm

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

ckeck_outputYöntemi kullanınsubprocess

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

Sonunda dizeyi ayrıştırın

for line in res.splitlines():

Umarım yardımcı olur, mutlu kodlama

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.