Python'dan harici bir komut çağırma


Yanıtlar:


4694

Standart kitaplıktaki alt işlem modülüne bakın :

import subprocess
subprocess.run(["ls", "-l"])

Avantajı subprocessvs. systemonu (alabilirsiniz daha esnek olmasıdır stdout, stderr"gerçek" durum kodu, daha iyi hata işleme, vs ...).

Resmi belgeler önerir subprocessalternatif üzerinde modülü os.system():

subprocessModül yeni süreçler yumurtlama ve onların sonuçlarını almak için, daha güçlü olanaklar sağlar; bu modülü kullanmak bu işlevi kullanmaktan daha çok tercih edilir [ os.system()].

Belgedeki Eski İşlevleri Alt İşlem Modülü ile Değiştirme bölümü subprocessbazı yararlı tariflere sahip olabilir.

3.5'ten önceki Python sürümleri için şunu kullanın call:

import subprocess
subprocess.call(["ls", "-l"])

Değişken ikameyi kullanmanın bir yolu var mı? IE echo $PATHkullanarak yapmaya çalıştım call(["echo", "$PATH"]), ama $PATHherhangi bir yerine koymak yerine gerçek dizeyi yankıladı . PATH ortam değişkenini alabileceğimi biliyorum, ama komutun tam olarak bash'de yapmışım gibi davranmanın kolay bir yolu olup olmadığını merak ediyorum.
Kevin Wheeler

@KevinWheeler Bunun shell=Trueçalışması için kullanmanız gerekecek .
SethMMorton

38
@KevinWheeler Kullanmamalısınız shell=True, bu amaçla Python os.path.expandvars ile birlikte gelir . Durumda da yazabilirsiniz: os.path.expandvars("$PATH"). @SethMMorton lütfen yorumunuzu tekrar gözden geçirin -> Neden shell kullanmıyorsunuz = True
Murmel

çağrı engelliyor mu? yani bir fordöngüde birden çok komut çalıştırmak istiyorsanız python betiğimi engellemeden nasıl yapabilirim? Ben sadece bir sürü çalıştırmak istiyorum komutun çıktı umurumda değil.
Charlie Parker

4
Parametreleri olan bir komuttan , subprocessne zaman kullanılabileceği bir listeden bir liste oluşturmak istiyorsanız , bunu yapmanın kolay bir yolu için shell=Falsekullanın docs.python.org/2/library/shlex.html#shlex.splitshlex.split
Daniel F

2983

Dış programları çağırmanın yollarının ve her birinin avantaj ve dezavantajlarının bir özeti:

  1. os.system("some_command with args")komutu ve bağımsız değişkenleri sisteminizin kabuğuna iletir. Bu çok hoş çünkü aslında bu şekilde birden fazla komutu aynı anda çalıştırabilir ve kanallar ile giriş / çıkış yeniden yönlendirmesini ayarlayabilirsiniz. Örneğin:

    os.system("some_command < input_file | another_command > output_file")  

Bununla birlikte, bu uygun olsa da, boşluklar, vb. Gibi kabuk karakterlerinden kaçmayı elle işlemeniz gerekir. Diğer yandan, bu aynı zamanda aslında harici programlar değil, sadece kabuk komutları olan komutları çalıştırmanıza izin verir. Belgelere bakın .

  1. stream = os.popen("some_command with args")os.systembu işlem için standart girdi / çıktıya erişmek için kullanabileceğiniz dosya benzeri bir nesne vermesi dışında aynı işlemi yapar. Tümünün i / o'yu biraz farklı şekilde ele alan 3 farklı popen varyantı vardır. Her şeyi bir dize olarak iletirseniz, komutunuz kabuğa aktarılır; onları bir liste olarak iletirseniz, hiçbir şeyden kaçma konusunda endişelenmenize gerek yoktur. Belgelere bakın .

  2. PopenSınıf subprocessmodülü. Bunun yerine geçmesi amaçlanmıştır, os.popenancak bu kadar kapsamlı olması nedeniyle biraz daha karmaşık olmanın dezavantajı vardır. Örneğin, şöyle diyeceksiniz:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    onun yerine:

    print os.popen("echo Hello World").read()

    ancak tüm seçeneklerin 4 farklı popen işlevi yerine tek bir sınıfta olması güzel. Belgelere bakın .

  3. callİşlev subprocessmodülü. Bu temelde Popensınıf gibidir ve aynı argümanların tümünü alır, ancak komut tamamlanana ve size dönüş kodunu verene kadar bekler. Örneğin:

    return_code = subprocess.call("echo Hello World", shell=True)  

    Belgelere bakın .

  4. Python 3.5 veya subprocess.runüstündeyseniz, yukarıdakine çok benzer, ancak daha esnek olan ve CompletedProcesskomutun yürütülmesi tamamlandığında bir nesneyi döndüren yeni işlevi kullanabilirsiniz .

  5. Os modülü ayrıca bir C programında bulunan tüm fork / exec / spawn işlevlerine sahiptir, ancak bunları doğrudan kullanmanızı önermiyorum.

subprocessModül muhtemelen Kullandığınız olmalıdır.

Son olarak, kabuk tarafından bir dize olarak yürütülecek son komutu ilettiğiniz tüm yöntemlerde ve bu komuttan kaçmaktan sorumlu olduğunuzu lütfen unutmayın. Geçirdiğiniz dizenin herhangi bir bölümüne tam olarak güvenilemiyorsa , ciddi güvenlik etkileri vardır . Örneğin, kullanıcı dizenin bir kısmını / herhangi bir kısmını giriyorsa. Emin değilseniz, bu yöntemleri yalnızca sabitlerle kullanın. Etkileri hakkında bir ipucu vermek için şu kodu göz önünde bulundurun:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

ve kullanıcının "annem beni sevmediğini && rm -rf /" bir şeyler girdiğini ve tüm dosya sistemini silebileceğini hayal edin.


22
Güzel cevap / açıklama. Bu cevap Python'un bu makalede anlatılan sloganını nasıl haklı çıkarıyor? fastcompany.com/3026446/… "Stilistik olarak, Perl ve Python'un farklı felsefeleri var. Perl'in en iyi bilinen sloganları" Bunu Yapmanın Birden Fazla Yolu Var ". Python bunu yapmanın bariz bir yoluna sahip olacak şekilde tasarlanmıştır. diğer yol! Perl'de bir komutu yürütmenin sadece iki yolunu biliyorum - geri-işaretini veya open.
Jean

12
Python 3.5+ kullanıyorsanız, kullanın subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run
anka kuşu

4
Tipik olarak bilmesi gereken şey, çocuk sürecinin STDOUT ve STDERR ile ne yapılması gerektiğidir, çünkü eğer göz ardı edilirse, bazı (oldukça yaygın) koşullar altında, sonunda çocuk süreci STDOUT'a (STDERR de yazmak için) bir sistem çağrısı gönderir. bu, OS tarafından işlem için sağlanan çıktı arabelleğini aşacaktır ve işletim sistemi, bazı işlem bu tampondan okunana kadar bloke olmasına neden olacaktır. Yani, şu anda tavsiye edilen yollar, subprocess.run(..)tam olarak ne yaptığını , "Bu, varsayılan olarak stdout veya stderr'yi yakalamak gelmez." ima etmek? Peki ya subprocess.check_output(..)STDERR?
Evgeni Sergeev

2
@ Pitto evet, ancak örnek tarafından yürütülen şey bu değil. echoGeçirilen dizenin ön kısmına dikkat edin Popen? Yani tam komut olacak echo my mama didnt love me && rm -rf /.
Chris Arndt

6
Bu muhtemelen yanlış bir yol. Çoğu insanın sadece subprocess.run()ya da onun büyük kardeşlerine ihtiyacı vardır subprocess.check_call(). Bu yeterli değil durumlar için, bkz subprocess.Popen(). os.popen()belki de hiç bahsedilmemeli, hatta "kendi çatalını / exec / spawn kodunu hacklemeden" sonra bile gelmemelidir.
tripleee

358

Tipik uygulama:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

Borudaki stdoutverilerle istediğinizi yapmakta özgürsünüz . Aslında, bu parametreleri ( stdout=ve stderr=) atlayabilirsiniz ve bu şekilde davranacaktır os.system().


44
.readlines()tüm satırları aynı anda okur , yani alt işlem çıkana kadar bloke olur (borunun ucunu kapatır). Gerçek zamanlı olarak okumak için (arabellekleme sorunu yoksa) şunları yapabilirsiniz:for line in iter(p.stdout.readline, ''): print line,
jfs

1
"Arabelleğe alma sorunu yoksa" ile ne demek istediğinizi açıklayabilir misiniz? İşlem kesinlikle engellenirse, alt işlem çağrısı da engeller. Aynı şey orijinal örneğim için de olabilir. Arabelleğe alma konusunda başka ne olabilir?
EmmEff

15
Çocuk işlem hattı tamponlama böylece yerine etkileşimli olmayan modda blok arabelleğe kullanabilir p.stdout.readline()(not: bir sucunda) alt onun tampon doldurana kadar herhangi bir veri olmaz. Çocuk çok fazla veri üretmezse, çıktı gerçek zamanlı olmayacaktır. Q'daki ikinci nedene bakın : Neden sadece bir boru (popen ()) kullanmıyorsunuz? . Bu cevapta bazı geçici çözümler sunulmaktadır (pexpect, pty, stdbuf)
jfs

4
arabelleğe alma sorunu yalnızca gerçek zamanlı çıktı almak istiyorsanız ve tüm veriler alınana kadar hiçbir şey yazdırmayan kodunuz için geçerli değilse önemlidir
jfs

3
Bu cevap zamanı geldi, ancak artık Popenbasit görevler için tavsiye etmemeliyiz . Bu da gereksiz yere belirtir shell=True. subprocess.run()Cevaplardan birini deneyin .
tripleee

230

Çocuk sürecini çağıran süreçten ayırmaya ilişkin bazı ipuçları (alt süreçte arka planda başlanması)

Bir CGI betiğinden uzun bir görev başlatmak istediğinizi varsayalım. Yani, alt işlem CGI betiği yürütme işleminden daha uzun yaşamalıdır.

Alt işlem modülü belgelerinden klasik örnek:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

Buradaki fikir, longtask.py bitinceye kadar 'alt işlem çağrısı' satırında beklemek istememenizdir. Ancak örnekten 'burada biraz daha kod' satırından sonra ne olduğu belli değil.

Hedef platformum FreeBSD'ydi, ancak geliştirme Windows'taydı, bu yüzden önce Windows'ta sorunla karşılaştım.

Windows'ta (Windows XP), longtask.py çalışmasını bitirinceye kadar üst işlem tamamlanmaz. Bir CGI betiğinde istediğiniz şey değildir. Sorun Python'a özgü değildir; PHP topluluğunda problemler aynıdır.

Çözüm DETACHED_PROCESS İşlem Oluşturma Bayrağını Windows API'sındaki temel CreateProcess işlevine iletmektir. Pywin32'yi kurduysanız, bayrağı win32process modülünden içe aktarabilirsiniz, aksi takdirde kendiniz tanımlamanız gerekir:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksun, aşağıdaki yorumda, anlamsal olarak doğru bayrağın CREATE_NEW_CONSOLE (0x00000010) * /

FreeBSD'de başka bir sorunumuz daha var: üst süreç bittiğinde, alt süreçleri de bitirir. Ve bu da bir CGI betiğinde istediğiniz şey değil. Bazı deneyler, sorunun sys.stdout paylaşımında olduğunu gösterdi. Ve çalışma çözümü şuydu:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Diğer platformlarda kodu kontrol etmedim ve FreeBSD'de davranışın nedenlerini bilmiyorum. Herkes bilirse, lütfen fikirlerinizi paylaşın. Python'da arka plan işlemlerini başlatmaya gitmek, henüz hiç ışık tutmaz.


pydev + tutulması py2exe uygulamaları geliştirme ile olası bir "ilginç" fark ettim. i eclipse çıktı penceresi sona ermiyordu çünkü ana komut dosyası kopuk olmadığını söylemek mümkün; komut dosyası tamamlanmasına rağmen yine de döndürmeyi beklemektedir. Ancak, ben bir py2exe yürütülebilir derleme çalıştı, beklenen davranış oluşur (müstakil olarak çalışır, sonra çıkar). emin değilim, ama yürütülebilir adı artık işlem listesinde değil. bu tüm yaklaşımlar için geçerlidir (os.system ("start *"), os.P_DETACH ile os.spawnl, alt protokoller, vb.)
maranas

1
CREATE_NEW_PROCESS_GROUP bayrağına da ihtiyacınız olabilir. Bkz POPEN acil çocuk sonlandırdı bile alt süreç bekliyor
jfs

5
Aşağıdakiler yanlış: "[o] n pencereleri (win xp), longtask.py çalışmasını bitirinceye kadar üst işlem tamamlanmaz". Üst öğe normal şekilde çıkacaktır, ancak konsol penceresi (conhost.exe örneği) yalnızca en son eklenen işlem çıktığında kapanır ve alt öğe üst konsolunu devralmış olabilir. Ayar DETACHED_PROCESSiçinde creationflagsmiras veya bir konsol oluşturmasını çocuğu önleyerek kaçınır bu. Bunun yerine yeni bir konsol istiyorsanız, CREATE_NEW_CONSOLE(0x00000010) kullanın .
Eryk Sun

1
Ayrık bir süreç olarak yürütmenin yanlış olduğu anlamına gelmiyordum. Bununla birlikte, dosyalara, borulara veya os.devnullbazı konsol programlarının bir hatayla çıkış yaptığı için standart tanıtıcıları ayarlamanız gerekebilir . Alt işlemin kullanıcıyla üst işlemle aynı anda etkileşime girmesini istediğinizde yeni bir konsol oluşturun. Her ikisini de tek bir pencerede yapmaya çalışmak kafa karıştırıcı olurdu.
Eryk Sun

1
Sürecin arka planda çalışmasını sağlayan OS-agnostik bir yolu yok mu?
Charlie Parker

152
import os
os.system("your command")

Komutun temizlenmediği için bunun tehlikeli olduğunu unutmayın. 'Os' ve 'sys' modülleri ile ilgili dokümantasyon için google'a bırakıyorum. Benzer şeyler yapacak bir sürü işlev (exec * ve spawn *) vardır.


6
Neredeyse on yıl önce ne demek istediğimi bilmiyorum (tarihi kontrol edin!), Ama tahmin etmek zorunda kalsaydım, hiçbir doğrulama yapılmazdı.
nimish

1
Bu şimdi subprocessbiraz daha çok yönlü ve taşınabilir bir çözüm olarak gösterilmelidir. Harici komutları çalıştırmak elbette doğası gereği kaydedilemez (komutun desteklemeniz gereken her mimaride mevcut olduğundan emin olmanız gerekir) ve harici bir komut olarak kullanıcı girişini geçmek doğal olarak güvensizdir.
tripleee

1
Bu adama zaman damgasını not edin: "doğru" cevapta 40x oy vardır ve cevap # 1'dir.
18'i 18

NodeJS malzemelerini çalıştırmak için benim için çalışan tek çözüm.
Nikolay Shindarov

148

Ben kullanarak tavsiye ediyorum altişlem sizin için kaçan kabuk ve çok daha güvenli nedenle çünkü modülü yerine os.system.

subprocess.call(['ping', 'localhost'])

Parametreleri olan bir komuttan , subprocessne zaman kullanılabileceği bir listeden bir liste oluşturmak istiyorsanız , bunu yapmanın kolay bir yolu için shell=Falsekullanın docs.python.org/2/library/shlex.html#shlex.split ( docs.python.org/2/library/subprocess.html#popen-constructor ) dokümanına göre önerilen yol budurshlex.split
Daniel F

6
Bu yanlış: " kabuk sizin için kaçan ve bu nedenle çok daha güvenli ". alt süreç kabuk kaçmayı yapmaz, alt süreç komutunuzu kabuktan geçirmez, bu nedenle kabuk kaçışına gerek yoktur.
Yalan Ryan

144
import os
cmd = 'ls -al'
os.system(cmd)

Komutun sonuçlarını döndürmek istiyorsanız, kullanabilirsiniz os.popen. Ancak, diğer yanıtların iyi kapsadığı alt işlem modülü lehine sürüm 2.6'dan bu yana kullanımdan kaldırılmıştır .



Sonucu os.system çağrısıyla da kaydedebilirsiniz, çünkü UNIX kabuğunun kendisi gibi çalışır, örneğin os.system ('ls -l> test2.txt')
Stefan Gruenwald

97

Python ile harici komutları çağırmanıza izin veren birçok farklı kitaplık var. Her kütüphane için bir açıklama verdim ve harici bir komut çağırma örneği gösterdim. Örnek olarak kullandığım komut ls -l(tüm dosyaları listele). Kütüphanelerden herhangi biri hakkında daha fazla bilgi edinmek isterseniz, her birinin belgelerini listeledim ve bağladım.

Kaynaklar:

Bunların hepsi kütüphaneler:

Umarım bu hangi kütüphaneyi kullanacağınıza karar vermenize yardımcı olacaktır :)

altişlem

Alt işlem, harici komutları çağırmanıza ve bunları giriş / çıkış / hata kanallarına (stdin, stdout ve stderr) bağlamanıza olanak tanır. Alt işlem komutları çalıştırmak için varsayılan seçimdir, ancak bazen diğer modüller daha iyidir.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

işletim sistemi

os "işletim sistemine bağlı işlevsellik" için kullanılır. Harici komutları os.systemve ile çağırmak için de kullanılabilir os.popen(Not: Ayrıca bir subprocess.popen vardır). os her zaman kabuğu çalıştıracak ve kullanması gerekmeyen veya nasıl kullanılacağını bilmeyen insanlar için basit bir alternatiftir subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

sh, programları sanki işlevmiş gibi çağırmanızı sağlayan bir alt işlem arabirimidir. Bir komutu birden çok kez çalıştırmak istiyorsanız bu yararlıdır.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

plumbum

plumbum "script benzeri" Python programları için bir kütüphanedir. Gibi işlevler gibi programları çağırabilirsiniz sh. Plumbum, kabuksuz bir boru hattı çalıştırmak istiyorsanız yararlıdır.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

pexpect

pexpect, çocuk uygulamalarını oluşturmanıza, kontrol etmenize ve çıktılarında desen bulmanıza olanak tanır. Bu, Unix'te tty bekleyen komutlar için alt işleme daha iyi bir alternatiftir.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

kumaş

fabric bir Python 2.5 ve 2.7 kütüphanesidir. Yerel ve uzak kabuk komutlarını yürütmenizi sağlar. Yapı, komutları güvenli bir kabukta (SSH) çalıştırmak için basit bir alternatiftir

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

elçi

elçi "insanlar için alt süreç" olarak bilinir. subprocessModülün çevresinde kolaylık sağlayan bir ambalaj olarak kullanılır .

r = envoy.run("ls -l") # Run command
r.std_out # get output

komutlar

commandsiçin sarmalayıcı işlevler içerir os.popen, ancak subprocessdaha iyi bir alternatif olduğu için Python 3'ten kaldırılmıştır .

Düzenleme JF Sebastian'ın yorumuna dayanıyordu.


74

Her zaman fabricböyle şeyler için kullanıyorum:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Ama bu iyi bir araç gibi görünüyor: sh(Python alt işlem arayüzü) .

Bir örneğe bakın:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

73

"Pexpect" Python kütüphanesini de kontrol edin.

Harici programların / komutların, hatta ssh, ftp, telnet vb. Etkileşimli kontrolüne izin verir. Sadece şöyle bir şey yazabilirsiniz:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

70

Standart kütüphane ile

Alt işlem modülünü kullanın (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

Önerilen standart yöntemdir. Ancak, daha karmaşık görevler (borular, çıktılar, girdiler, vb.) Oluşturmak ve yazmak sıkıcı olabilir.

Python sürümü hakkında not: Hala Python 2 kullanıyorsanız, subprocess.call benzer şekilde çalışır.

ProTip: shlex.split için komutu ayrıştırmak için yardımcı olabilir run, callve diğer subprocessdurumda fonksiyonları istemediğiniz (ya yapamazsın!) Listeleri şeklinde bunları sağlamak:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Harici bağımlılıklar ile

Dış bağımlılıklara aldırmazsanız , plumbum kullanın :

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

En iyi subprocesssarıcıdır. Platformlar arası, yani hem Windows hem de Unix benzeri sistemlerde çalışır. Tarafından yükleyin pip install plumbum.

Başka bir popüler kütüphane sh :

from sh import ifconfig
print(ifconfig('wlan0'))

Ancak, shWindows desteği düştü, bu yüzden eskisi kadar harika değil. Tarafından yükleyin pip install sh.


69

Aradığınız komutun çıktısına ihtiyacınız varsa subprocess.check_output (Python 2.7+) kullanabilirsiniz.

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Ayrıca shell parametresini de not edin .

Kabuk ise True, belirtilen komut kabuk üzerinden yürütülür. Python'u öncelikle sistem kabuklarının çoğunda sunduğu gelişmiş kontrol akışı için kullanıyorsanız ve yine de kabuk boruları, dosya adı joker karakterleri, ortam değişkeni genişletmesi ve ~ bir kullanıcının evine genişletilmesi gibi diğer kabuk özelliklerine kolayca erişmek istiyorsanız faydalı olabilir. dizin. Ancak, not Python kendisinin uygulamalarını sunduğu birçok kabuk gibi özellikleri (özellikle glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), ve shutil).


1
check_outputDize yerine bir liste gerektiren bir not . Çağrınızı geçerli kılmak için alıntı yapılan alanlara güvenmiyorsanız, bunu yapmanın en basit, en kolay yolu subprocess.check_output("ls -l /dev/null".split()).
Bruno Bronosky

56

Komutlarımı bu şekilde çalıştırıyorum. Bu kodda ihtiyacınız olan her şey var

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

3
Okunabilirliği artırırsa, sabit kodlu komutlar için kabul edilebilir olduğunu düşünüyorum.
Adam Matan

54

Güncelleme:

subprocess.runkodunuzun önceki Python sürümleriyle uyumluluğu sürdürmesi gerekmiyorsa , Python 3.5'ten itibaren önerilen yaklaşımdır . Daha tutarlı ve Elçi ile benzer kullanım kolaylığı sunuyor. (Boru basit düşünce olarak değil. Bkz nasıl bu soruyu .)

Belgelerden bazı örnekler .

Bir işlem çalıştırın:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Başarısız çalıştırmada yükseltme:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Yakalama çıkışı:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Orijinal cevap:

Elçi'yi denemenizi tavsiye ederim . Alt süreç için bir sargıdır, bu da eski modülleri ve işlevleri değiştirmeyi amaçlamaktadır . Elçi insanlar için bir alt süreçtir.

README'den örnek kullanım :

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Etrafında boru şeyler:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

os.systemTamam, ama tür tarihli. Ayrıca çok güvenli değil. Bunun yerine deneyin subprocess. subprocesssh'yi doğrudan çağırmaz ve bu nedenle daha güvenlidir os.system.

Daha fazla bilgiyi buradan edinebilirsiniz .


2
Genel öneriyi kabul ederken, subprocesstüm güvenlik sorunlarını ortadan kaldırmaz ve kendi başına bazı sinir bozucu sorunları vardır.
tripleee

36

Python'da harici bir komut çağırma

Basit, kullanım subprocess.run, bir CompletedProcessnesne döndürür :

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Neden?

Python 3.5 itibariyle, belgeler subprocess.run öğesini önerir :

Alt süreçleri çağırmak için önerilen yaklaşım, işleyebileceği tüm kullanım durumları için run () işlevini kullanmaktır. Daha gelişmiş kullanım durumları için, temeldeki Popen arabirimi doğrudan kullanılabilir.

İşte mümkün olan en basit kullanıma bir örnek - ve tam olarak istendiği gibi yapıyor:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

runkomutun başarıyla bitmesini bekler, sonra bir CompletedProcessnesneyi döndürür . Bunun yerine TimeoutExpired(bir timeout=argüman verirseniz ) veya CalledProcessError(başarısız olursa ve geçerseniz check=True) yükselebilir .

Yukarıdaki örnekten çıkarım yapabileceğiniz gibi, hem stdout hem de stderr varsayılan olarak kendi stdout'unuza ve stderr'ye aktarılır.

Döndürülen nesneyi inceleyebilir ve verilen komutu ve dönüş kodunu görebiliriz:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Çıktı yakalama

Çıktıyı yakalamak istiyorsanız subprocess.PIPE, uygun olana geçebilir stderrveya stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Sürüm bilgisinin stdout yerine stderr'a konmasını ilginç ve biraz mantıksız buluyorum.)

Bir komut listesi iletme

Manuel olarak bir komut dizesi sağlamaktan (sorunun önerdiği gibi) programlı olarak oluşturulmuş bir dize sağlamaya kolayca geçilebilir. Programlı olarak dizeler oluşturmayın. Bu potansiyel bir güvenlik sorunudur. Girdiye güvenmediğinizi varsaymak daha iyidir.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Not, sadece argskonumsal olarak geçilmelidir.

Tam İmza

Kaynakta ve şu şekilde gösterildiği gibi gerçek imza help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargsVe kwargsverilen Popenyapıcı. alt işlemin stdinine inputbağlanacak bir bayt dizesi (veya kodlama belirtilirse unicode veya universal_newlines=True) olabilir.

Belgeler açıklayabilir timeout=ve check=Trueyapabileceğimden daha iyi:

Zaman aşımı argümanı Popen.communicate () öğesine iletilir. Zaman aşımı süresi dolarsa, alt süreç öldürülecek ve beklenecektir. Alt süreç sona erdikten sonra TimeoutExpired özel durumu yeniden yükseltilecektir.

Kontrol doğruysa ve işlem sıfırdan farklı bir çıkış koduyla çıkarsa, CalledProcessError istisnası yükseltilir. Bu kural dışı durumun öznitelikleri, yakalandıysa bağımsız değişkenleri, çıkış kodunu ve stdout ve stderr öğelerini içerir.

ve bu örnek check=True, gelebileceğimden daha iyidir:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Genişletilmiş İmza

Dokümanlarda verildiği gibi genişletilmiş bir imza:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Bunun yalnızca argüman listesinin konumsal olarak geçirilmesi gerektiğini gösterdiğini unutmayın. Bu nedenle, kalan bağımsız değişkenleri anahtar kelime bağımsız değişkenleri olarak iletin.

popen

PopenBunun yerine ne zaman kullanılır ? Sadece argümanlara dayanarak kullanım davası bulmakta zorlanıyordum. PopenBununla birlikte, doğrudan kullanımı poll, 'send_signal', 'terminate' ve 'wait' gibi yöntemlerine erişmenizi sağlar .

Burada Popen kaynakta verilen imza . Bu (en aksine help(Popen)) bilginin en kesin kapsüllenmesi olduğunu düşünüyorum :

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Ama daha bilgilendirici Popen belgeler :

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Yeni bir süreçte bir alt program yürütün. POSIX'te sınıf, alt programı yürütmek için os.execvp () benzeri davranışı kullanır. Windows'ta, sınıf Windows CreateProcess () işlevini kullanır. Popen ile ilgili argümanlar aşağıdaki gibidir.

İle ilgili kalan dokümantasyonu anlama Popen okuyucu için bir alıştırma olarak bırakılacaktır.


Birincil işlem ile bir alt işlem arasındaki iki yönlü iletişimin basit bir örneğini burada bulabilirsiniz: stackoverflow.com/a/52841475/1349673
James Hirschorn

İlk örnekte shell=Truekomutun liste halinde olması veya (daha iyisi) geçmesi gerekir.
tripleee

33

Orada da Plumbum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

28

kullanın:

import os

cmd = 'ls -al'

os.system(cmd)

os - Bu modül işletim sistemine bağlı işlevselliği kullanmak için taşınabilir bir yol sağlar.

Daha fazla osfonksiyon için, dokümantasyon burada .


2
aynı zamanda kullanımdan kaldırıldı. alt süreç kullan
Corey Goldberg

28

Bu kadar basit olabilir:

import os
cmd = "your command"
os.system(cmd)

1
Bu, PEP-324'te çok daha ayrıntılı olarak açıklanan dezavantajları göstermez . Belgelendirme, os.systemaçıkça lehine kaçınmayı önerir subprocess.
tripleee

25

Sadeliği için shell_command'ı çok seviyorum . Alt işlem modülünün üzerine inşa edilmiştir.

Belgelerden bir örnek:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

Burada daha önce bahsedilmeyen başka bir fark var.

subprocess.Popen<komut> seçeneğini bir alt işlem olarak yürütür. Benim durumumda, başka bir programla iletişim kurması gereken <a> dosyasını yürütmem gerekiyor <b>.

Alt süreci denedim ve yürütme başarılı oldu. Ancak <b> <a> ile iletişim kuramadı. Her ikisini de terminalden çalıştırdığımda her şey normal.

Bir tane daha: (NOT: kwrite diğer uygulamalardan farklı davranır. Aşağıdakileri Firefox ile denerseniz, sonuçlar aynı olmayacaktır.)

Eğer denerseniz os.system("kwrite"), program akış donar kullanıcı kapanır KWRITE kadar. Bunun üstesinden gelmek için denedim os.system(konsole -e kwrite). Bu zaman programı akmaya devam etti, ancak kwrite konsolun alt süreci oldu.

Herkes kwrite'ı bir alt işlem olarak çalıştırmaz (yani sistem monitöründe ağacın en sol kenarında görünmelidir).


1
"Kimse kwrite'ı bir alt işlem olarak çalıştırmaz" derken neyi kastediyorsunuz ?
Peter Mortensen

23

os.systemsonuçları depolamanıza izin vermez, bu nedenle sonuçları bir listede veya başka bir şeyde saklamak istiyorsanız, bir subprocess.callçalışma.


22

subprocess.check_calldönüş değerlerini test etmek istemiyorsanız kullanışlıdır. Herhangi bir hata için bir istisna atar.


22

Ben shlex (alıntı dizeleri kaçmak için) ile birlikte alt işlem kullanma eğilimindedir :

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

17

Utanmaz fiş, bunun için bir kütüphane yazdım: P https://github.com/houqp/shell.py

Temelde şu an için popen ve shlex için bir sargı. Ayrıca boru komutlarını da destekler, böylece Python'da komutları daha kolay zincirleyebilirsiniz. Böylece aşağıdakileri yapabilirsiniz:

ex('echo hello shell.py') | "awk '{print $2}'"

16

Windows sadece alabilirsiniz subprocessmodülü ve arayarak dış komutları çalıştırın subprocess.Popen(), subprocess.Popen().communicate()ve subprocess.Popen().wait()aşağıdaki gibi:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Çıktı:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

15

Linux altında, bağımsız olarak yürütülecek (python komut dosyası sona erdikten sonra çalışmaya devam edecek) harici bir komut çağırmak isterseniz, basit bir kuyruğu görev biriktiricisi veya at komutu olarak kullanabilirsiniz.

Görev biriktiricili bir örnek:

import os
os.system('ts <your-command>')

Görev biriktirici ( ts) ile ilgili notlar :

  1. Çalıştırılacak eşzamanlı işlemlerin sayısını ("yuvalar") şu şekilde ayarlayabilirsiniz:

    ts -S <number-of-slots>

  2. Yüklemek tsiçin yönetici ayrıcalıkları gerekmez. Basit bir şekilde kaynaktan indirip derleyebilir make, yolunuza ekleyebilirsiniz ve işiniz bitti.


1
tsişaretçi athafif faydalı olsa da, bildiğim herhangi bir dağıtımda standart değil . Muhtemelen de bahsetmelisiniz batch. Başka yerlerde olduğu gibi, os.system()öneri muhtemelen en azından subprocessönerilen değiştirilmesinden bahsetmelidir .
tripleee

15

Popen'i kullanabilir ve ardından prosedürün durumunu kontrol edebilirsiniz:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Alt süreci kontrol edin .


15

Ağ kimliği getirmesi openstack Neutron :

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Nova net listesinin çıktısı

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Çıktı baskı (NETWORKID)

27a74fcd-37c0-4789-9414-9531b7e3f126

os.popen()2016'da önerilmemelisiniz . Awk betiği kolayca yerel Python kodu ile değiştirilebilir.
tripleee
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.