Kabuk komutunu çalıştırma ve çıktıyı yakalama


908

Bir kabuk komutu yürütecek ve çıktısını bir dize olarak döndürecek bir işlev yazmak istiyorum , ne olursa olsun, bir hata veya başarı mesajı. Komut satırı ile elde ettiğim sonucun aynısını almak istiyorum.

Böyle bir şey yapacak bir kod örneği ne olurdu?

Örneğin:

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'

Yanıtlar:


1138

Bu sorunun cevabı kullandığınız Python sürümüne bağlıdır. En basit yaklaşım subprocess.check_outputişlevi kullanmaktır :

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_outputyalnızca bağımsız değişkenleri girdi olarak alan tek bir program çalıştırır. 1 Sonucu tam olarak yazdırıldığı gibi döndürür stdout. Giriş yazmanız gerekirse stdin, runveya Popenbölümlerine atlayın . Karmaşık kabuk komutlarını yürütmek istiyorsanız shell=True, bu cevabın sonundaki nota bakın .

Bu check_outputfonksiyon Python'un neredeyse tüm sürümlerinde hala yaygın olarak kullanılmaktadır (2.7+). 2 Ancak daha yeni sürümler için, artık önerilen yaklaşım değildir.

Modern Python sürümleri (3.5 veya üstü): run

Python 3.5 veya üstünü kullanıyorsanız ve geriye dönük uyumluluğa ihtiyacınız yoksa , yeni runişlev önerilir. subprocessModül için çok genel, yüksek düzeyli bir API sağlar . Bir programın çıktısını yakalamak için subprocess.PIPEbayrağı stdoutanahtar kelime değişkenine iletin. Ardından stdout, döndürülen CompletedProcessnesnenin özniteliğine erişin :

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Dönüş değeri bir bytesnesnedir, bu nedenle uygun bir dize istiyorsanız decodebuna ihtiyacınız olacaktır . Aranan işlemin UTF-8 kodlu bir dize döndürdüğü varsayılarak:

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

Bunların hepsi bir astarla sıkıştırılabilir:

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

İşlemin girdisine veri iletmek istiyorsanız , anahtar kelime bağımsız değişkenine stdinbir bytesnesne inputiletin:

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

Hataları stderr=subprocess.PIPE(yakalama result.stderr) veya stderr=subprocess.STDOUT( result.stdoutnormal çıktıyla birlikte yakalama ) ileterek yakalayabilirsiniz . Güvenlik endişe verici değilse, shell=Trueaşağıdaki notlarda açıklandığı gibi ileterek daha karmaşık kabuk komutları da çalıştırabilirsiniz .

Bu, eski işleri yapmanın biçimine kıyasla biraz karmaşıklık katıyor. Ama bence getiriye değer: şimdi runsadece işlevle yapmak için ihtiyacınız olan hemen hemen her şeyi yapabilirsiniz .

Eski Python sürümleri (2.7-3.4): check_output

Python'un daha eski bir sürümünü kullanıyorsanız ya da geriye doğru uyumluluğa ihtiyacınız varsa, check_outputişlevi yukarıda kısaca açıklandığı gibi kullanabilirsiniz. Python 2.7'den beri mevcuttur.

subprocess.check_output(*popenargs, **kwargs)  

Alır Popen(aşağıya bakınız) ile aynı argümanları alır ve programın çıktısını içeren bir dize döndürür. Bu cevabın başlangıcında daha ayrıntılı bir kullanım örneği var. Python 3.5 ve daha büyük check_outputsürümlerde run, check=Trueve ile çalışmak ve stdout=PIPEyalnızca stdoutöznitelik döndürmekle eşdeğerdir .

Sen geçebilir stderr=subprocess.STDOUTdöndü çıktıda yer aldığını hata iletileri sağlamak için - ama Python geçen bazı sürümlerinde stderr=subprocess.PIPEiçin check_outputteneke neden çözümsüzlüklerle . Güvenlik endişe verici değilse, shell=Trueaşağıdaki notlarda açıklandığı gibi ileterek daha karmaşık kabuk komutları da çalıştırabilirsiniz .

İşlemden boru hattına geçmeniz stderrveya işlemden check_outputgeçirmeniz gerekiyorsa, görev kadar olmayacaktır. Bkz Popenbu durumda aşağıdaki örnekleri.

Karmaşık uygulamalar ve Python'un eski sürümleri (2.6 ve altı): Popen

Geriye dönük uyumluluğa ihtiyacınız varsa veya check_outputsağladığınızdan daha karmaşık bir işlevsellik istiyorsanız, doğrudan Popenalt işlemler için düşük düzeyli API'yi içine alan nesnelerle çalışmanız gerekir .

PopenYapıcı kabul eden , tek bir komut bağımsız değişken olmayan ya da bir liste bağımsız değişkenler herhangi bir sayıda, listedeki ayrı bir madde olarak, her takip ettiği ilk madde olarak bir komut ihtiva ederler. shlex.splitdizeleri uygun şekilde biçimlendirilmiş listelerde ayrıştırmaya yardımcı olabilir. Popennesneler ayrıca işlem GÇ yönetimi ve düşük düzeyli yapılandırma için bir dizi farklı argümanı da kabul eder .

Girdi ve yakalama çıktısı göndermek için communicate, neredeyse her zaman tercih edilen yöntemdir. De olduğu gibi:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

Veya

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

Ayarlarsanız stdin=PIPE, communicateverileri işleme yoluyla şu yolla aktarmanıza da olanak tanır stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

Not Aaron Hall'un cevabı bazı sistemlerde belirtir, sette gerekebilir stdout, stderrve stdintüm PIPE(veya DEVNULL) almak için communicatehiç işe.

Bazı nadir durumlarda, karmaşık, gerçek zamanlı çıktı yakalamaya ihtiyacınız olabilir. Vartec'in cevabı, ileriye doğru bir yol önerir, ancak communicatedikkatli kullanılmadıklarında çıkmazlara eğilimli olanlar dışındaki yöntemler .

Yukarıdaki tüm işlevlerde olduğu gibi, güvenlik bir endişe olmadığında, daha karmaşık kabuk komutlarını ileterek çalıştırabilirsiniz shell=True.

notlar

1. Kabuk komutlarını çalıştırma: shell=Trueargüman

Normal olarak, her bir çağrı run, check_outputya da Popenyapıcı bir yürüten tek bir programı . Bu süslü bash tarzı borular anlamına gelmez. Karmaşık kabuk komutlarını çalıştırmak istiyorsanız, shell=Trueher üç işlevin de desteklediği geçiş yapabilirsiniz .

Ancak bunu yapmak güvenlik endişelerini arttırır . Hafif komut dosyası oluşturmadan başka bir şey yapıyorsanız, her işlemi ayrı ayrı çağırmak ve her birinden çıktıyı bir girdi olarak diğerine,

run(cmd, [stdout=etc...], input=other_output)

Veya

Popen(cmd, [stdout=etc...]).communicate(other_output)

Boruları doğrudan bağlama cazibesi güçlüdür; direnmek. Aksi takdirde, büyük olasılıkla çıkmazları göreceksiniz veya bunun gibi hacky şeyler yapmak zorunda kalacaksınız .

2. Unicode ile ilgili düşünceler

check_outputPython 2'de bir dize, ancak bytesPython 3'te bir nesne döndürür . Henüz yapmadıysanız unicode hakkında bilgi edinmek için biraz zaman ayırmaya değer .


5
Hem ile check_output()hem communicate()de süreç bitene kadar beklemek zorundasınız, poll()geldiği gibi çıktı alıyorsunuz. Gerçekten neye ihtiyacınız olduğuna bağlı.
vartec

2
Emin değil bu ancak Python sonraki sürümlerinde için geçerlidir, ancak değişken eğer outÇeşidi oldu <class 'bytes'>benim için. Bir dize olarak çıktı almak için şöyle yazdırmadan önce deşifre etmek zorunda kaldı:out.decode("utf-8")
PolyMesh

1
@par Geçtiğinde bu işe yaramaz shell=Truemı? Benim için çalışıyor. Buna gerek yok shlex.splitsen geçerken shell=True. shlex.splitkabuk olmayan komutlar içindir. Sanırım o parçayı çıkaracağım çünkü bu suları çamurluyor.
senderle

2
Python 3.5+ universal_newlines=True, sistemin varsayılan kodlamasında Unicode dizelerini geçirmenize ve çıkmanıza izin veren bir anahtar kelime argümanına izin verir. 3.7'de bu daha mantıklı olarak yeniden adlandırıldı text=True.
Üçlü '12

2
Python 3.6+ için kullanmak yerine encodingparametresini kullanabilirsiniz . subprocess.runresult.stdout.decode('utf-8')subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
Pierre

191

Bu çok daha kolaydır, ancak yalnızca Unix (Cygwin dahil) ve Python2.7'de çalışır.

import commands
print commands.getstatusoutput('wc -l file')

(Return_value, output) ile bir demet döndürür.

Hem Python2 hem de Python3'te çalışan bir çözüm için subprocessmodülü kullanın:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
Şimdi kullanımdan kaldırıldı, ancak alt süreç olmadan eski python sürümleri için çok
yararlı.check_output

22
Bunun Unix'e özgü olduğunu unutmayın. Örneğin Windows'da başarısız olur.
Zitrax

4
+1 Python 2.4'ün eski versiyonu üzerinde çalışmak zorundayım ve bu ÇOK yardımcı oldu
javadba

1
PIPE dude hadi tam kodu göster: subprocess.PIPE
Kyle Bridenstine

@KyleBridenstine cevapları düzenleyebilirsiniz.
Boris

106

Bunun gibi bir şey:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

Stderr'ı stdout'a yönlendiriyorum, tam olarak istediğiniz şey olmayabilir, ancak hata mesajlarını da istiyorum.

Bu işlev geldikçe satır satır verir (normalde çıktıyı bir bütün olarak almak için alt işlemin bitmesini beklemeniz gerekir).

Sizin durumunuz için kullanım:

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,

Potansiyel kilitlenmeyi waitve callişlevlerden kaçınmak için çıktıyı almak üzere bir çeşit aktif döngü uyguladığınızdan emin olun .
André Caron

@Gümüş Işık: işleminiz muhtemelen kullanıcıdan girdi bekliyor. Bir dosya PIPEiçin değer sağlamayı stdinve bu dosyayı en kısa sürede kapatmayı deneyin Popen.
André Caron

4
1: Bu ise, sonsuz bir döngü olduğunu retcodeolan 0. Kontrol olmalı if retcode is not None. Sen boş dizeleri verim olmamalıdır (hatta boş bir satır en az bir sembol '\ n' dir): if line: yield line. p.stdout.close()Sonunda arayın .
jfs

2
Ben ls -l / dirname ile kodu denedim ve dizinde çok daha fazla dosya varken iki dosya listeledikten sonra kırılır
Vasilis

3
@fuenfundachtzig: tüm çıktılar okunana .readlines()kadar geri dönmez ve bu nedenle belleğe sığmayan büyük çıktıları keser. Ayrıca alt işlemden çıktıktan sonra ara belleğe alınmış verilerin eksik kalmasını önlemek içinif retcode is not None: yield from p.stdout.readlines(); break
jfs

67

Vartec'in cevabı tüm satırları okumaz, bu yüzden aşağıdakileri yapan bir sürüm yaptım:

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

Kullanım, kabul edilen cevapla aynıdır:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

6
return iter(p.stdout.readline, b'')while döngüsü yerine kullanabilirsiniz
jfs

2
Bu çok güzel bir kullanımı, bunu bilmiyordum! Kodu güncelledim.
Max Ekman

Eminim stdout tüm çıktıyı tutar, tamponlu bir akış nesnesidir. Bir Popen tamamlandıktan sonra kalan tüm çıktıları tüketmek için çok benzer bir teknik kullanıyorum ve benim durumumda, çıkışı canlı olarak yakalamak için yürütme sırasında anket () ve readline'ı da kullanıyorum.
Max Ekman

Yanıltıcı yorumumu kaldırdım. Ben, teyit edebilir p.stdout.readline()çocuk süreç zaten çıkıldı olsa bile boş olmayan önceden tamponlu çıkışı döndürebilir ( p.poll()değilNone ) .
jfs

Bu kod çalışmıyor. Buraya bakın stackoverflow.com/questions/24340877/…
thang

61

Bu, birçok durumda çalışan zor ama süper basit bir çözümdür:

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

Komutun çıktısı ile geçici bir dosya (burada tmp) oluşturulur ve istediğiniz çıktıyı buradan okuyabilirsiniz.

Yorumlardan ilave not: Bir kerelik iş durumunda tmp dosyasını kaldırabilirsiniz. Bunu birkaç kez yapmanız gerekiyorsa, tmp'yi silmenize gerek yoktur.

os.remove('tmp')

5
Keskin ama süper basit + her yerde çalışır .. mktempSanırım dişli durumlarda çalışmak için ile birleştirebilirsiniz
Prakash Rajagaopal

2
Belki en hızlı yöntem, ama daha iyi os.remove('tmp')"fileless" yapmak için ekleyin .
XuMuK

@XuMuK Bir kerelik bir iş söz konusu olduğunda haklısınız. Eğer tekrarlayan bir
işse

1
eşzamanlılık için kötü, evresel işlevler için kötü, sistemi başlamadan önceki gibi terk etmemek için kötü (temizleme yok)
2mia

1
@ 2mia Açıkçası bir nedenden dolayı kolay! Dosyayı eşzamanlı okuma ve yazma için bir tür paylaşılan bellek olarak kullanmak istiyorsanız, bu iyi bir seçim değildir. Ancak, s.th. için bir komutun çıktısını almak gibi (örneğin ls veya find veya ...) iyi ve hızlı bir seçim olabilir. BTW basit bir sorun için hızlı bir çözüme ihtiyacınız varsa bence en iyisi. Bir boru hattına ihtiyacınız varsa, alt işlem sizin için daha verimli çalışır.
Mehdi Saman Booy

44

Aynı sorunu yaşadım ama bunu yapmanın çok basit bir yolunu buldum:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

Umarım yardımcı olur

Not: Bu çözüm, Python2'de subprocess.getoutput()çalışmadığından Python3'e özgüdür


Bu OP'nin problemini nasıl çözer? Lütfen detaylandırın.
RamenChef

4
Komut çıktısını dize olarak döndürür, bu kadar basit
azhar22k

1
Tabii ki, baskı Python 2 ile ilgili bir açıklamadır. Bunun bir Python 3 cevabı olduğunu anlayabilmelisiniz.

2
@Dev baskı (lar) geçerli python 2. altprocess.getoutput değil.
user48956

2
Çoğu kullanım durumunda, insanlar muhtemelen bunu isteyecektir: hatırlanması kolay, sonuçları çözmeniz gerekmez, vb.
bwv549

18

Herhangi bir kabuk komutunu çalıştırmak için aşağıdaki komutları kullanabilirsiniz. Bunları ubuntu üzerinde kullandım.

import os
os.popen('your command here').read()

Not: Bu, python 2.6'dan beri kullanımdan kaldırılmıştır. Şimdi kullanmalısın subprocess.Popen. Aşağıda örnek

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

2
2.6 sürümünden bu yana kullanımdan kaldırıldı
Filippo Vitale

1
@FilippoVitale Teşekkürler. Kullanımdan kaldırıldığını bilmiyordum.
Muhammed Hassan

1
Göre raspberrypi.stackexchange.com/questions/71547/... os.popen() Python 2.6 önerilmiyor, ancak edilir değil 3.x o kullanılarak uygulanır beri, Python 3.x kullanımdan kaldırılmış subprocess.Popen().
JL

12

Kilometreniz Değişebilir, @ senderle'ın Parthon 2.6.5 üzerinde Windows'ta Vartec'in çözümünü döndürmeye çalıştım, ancak hata alıyordum ve başka hiçbir çözüm işe yaramadı. Benim hata: WindowsError: [Error 6] The handle is invalid.

Beklediğim çıktıyı geri getirmek için her tutamağa PIPE atamam gerektiğini buldum - aşağıdakiler benim için çalıştı.

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

ve şöyle deyin, ( [0]grubun ilk öğesini alır, stdout):

run_command('tracert 11.1.0.1')[0]

Daha fazlasını öğrendikten sonra, bu boru argümanlarına ihtiyacım olduğuna inanıyorum çünkü farklı kulplar kullanan özel bir sistem üzerinde çalışıyorum, bu yüzden doğrudan std'leri kontrol etmek zorunda kaldım.

Konsol açılır pencerelerini durdurmak için (Windows ile) şunları yapın:

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
İlginç - bu bir Windows şey olmalı. İnsanların benzer hatalar almaları durumunda buna işaret eden bir not ekleyeceğim.
senderle

kullanmak DEVNULLyerine ait subprocess.PIPEyazmıyorsun eğer / aksi takdirde çocuk sürecini askıda kalabilir borudan okunması.
jfs

10

Aşağıdaki gereksinimlerle aynı sorunun biraz farklı bir tadı vardı:

  1. STDOUT mesajlarını STDOUT arabelleğinde biriktikçe yakalayın ve gönderin (yani gerçek zamanlı).
    • @vartec, bunu Pythonically, jeneratör kullanımı ve
      yukarıdaki 'verim' anahtar kelimesi ile çözdü
  2. Tüm STDOUT satırlarını yazdır ( STDOUT arabelleği tamamen okunmadan önce işlem yapılsa bile )
  3. İşlemi yüksek frekansta sorgulayarak CPU döngülerini boşa harcamayın
  4. Alt işlemin dönüş kodunu kontrol edin
  5. Sıfır olmayan bir hata dönüş kodu alırsak STDERR (STDOUT'tan ayrı) yazdırın.

Aşağıdaki cevapları bulmak için önceki cevapları birleştirdim ve ayarladım:

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

Bu kod, önceki yanıtlarla aynı şekilde yürütülür:

for line in run_command(cmd):
    print(line)

1
Uyku (.1) ilavesinin CPU döngülerini nasıl boşa harcamadığını açıklar mısınız?
Moataz Elmasry

2
p.poll()Çağrılar arasında herhangi bir uyku olmadan aramaya devam edersek, milyonlarca kez bu işlevi çağırarak CPU döngülerini boşa harcarız. Bunun yerine, işletim sistemine önümüzdeki 1/10 saniye için rahatsız edilmemize gerek olmadığını söyleyerek döngümüzü "kısaltırız", böylece diğer görevleri gerçekleştirebilir. (P.poll () öğesinin de uyuması olasıdır ve uyku bildirimimizi gereksiz kılar).
Aelfinn

5

İçin ilk komutu bölme subprocess zor ve hantal olabilir.

kullanım shlex.split()Kendinize yardım etmek için .

Örnek komut

git log -n 5 --since "5 years ago" --until "2 year ago"

Kod

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

shlex.split()Kod olmadan aşağıdaki gibi görünecektir

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()özellikle kabukta alıntı yapmanın tam olarak nasıl çalıştığını bilmiyorsanız kolaylık sağlar; ancak alıntıyı anlarsanız bu dizeyi manuel olarak listeye dönüştürmek ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']hiç de zor değildir.
Üçlü

4

Birden fazla dosyada bir kabuk komutu çalıştırmanız gerekiyorsa, bu benim için hile yaptı.

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

Düzenleme: Sadece Max Persson'un çözümünü JF Sebastian'ın önerisiyle gördüm. İleri gitti ve bunu dahil etti.


Popenya bir dizeyi kabul eder, ancak daha sonra ihtiyacınız olur shell=True, ya da bir argümanlar listesi; bu durumda ['nm', filename]dize yerine iletmeniz gerekir. İkincisi tercih edilir, çünkü kabuk burada herhangi bir değer sağlamadan karmaşıklık ekler. shell=TrueGörünüşe göre bir dize geçirmek Windows üzerinde çalışıyor, ancak bu herhangi bir sonraki Python sürümünde değişebilir.
Üçlü

2

@Senderle'a göre, benim gibi python3.6 kullanıyorsanız:

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

Tam olarak bash komutunu çalıştırdığınız gibi davranacak


Anahtar kelime bağımsız değişkenlerini yeniden keşfediyorsunuz check=True, universal_newlines=True. Başka bir deyişle subprocess.run(), kodunuzun yaptığı her şeyi zaten yapıyor.
Üçlü

1

subprocessPython modülünü kullanırsanız, STDOUT, STDERR ve komut kodunu ayrı ayrı işleyebilirsiniz. Komut arayan uygulaması için eksiksiz bir örnek görebilirsiniz. Tabii ki uzatabilirsiniztry..except .

Aşağıdaki işlev STDOUT, STDERR ve Return kodlarını döndürür, böylece bunları diğer komut dosyasında işleyebilirsiniz.

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

Başka bir kötü yeniden uygulama subprocess.run(). Tekerleği yeniden icat etme.
Üçlü

0

örneğin, yürütmek ('ls -ahl') farklılaştırılmış üç / dört olası getiri ve işletim sistemi platformları:

  1. çıktı yok, ancak başarıyla çalıştır
  2. boş satır çıktı, başarıyla çalıştır
  3. koşu başarısız
  4. bir şeyler çıkar, başarıyla çalıştır

aşağıdaki fonksiyon

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

Çıktı bir metin dosyasına yönlendirilebilir ve sonra tekrar okunabilir.

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

Elbette olabilir, ama neden yapmak istersiniz; ve niçin kabuğu geçmek yerine kullanasınız ki stdout=temp_file?
Üçlü

Aslında, genel olarak haklısınız ama benim ecls.exeörneğimde başka bir komut satırı aracı kullanıyor gibi görünüyor, bu yüzden basit yol bazen işe yaramadı.
MR

0

sadece curl kullanarak bunu yapmak için küçük bir bash betiği yazdı

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"
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.