Soru Python'da harici bir komut çağırmak


Bir Python komut dosyasından harici bir komutu nasıl çağırabilirim (Unix kabuğunda veya Windows komut isteminde yazmış gibi)?


3635
2017-09-18 01:35


Menşei




Cevaplar:


Bak alt işlem modülü standart kütüphanede:

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

Avantajı altişlem vs. sistem Bu daha esnek (stdout, stderr, "gerçek" durum kodu, daha iyi hata işleme, vb ... alabilirsiniz).

resmi belgeler önerir altişlem alternatif os.system üzerinden modül ():

altişlem modül, yeni süreçler oluşturmak ve sonuçlarını almak için daha güçlü olanaklar sağlar; Bu işlevi kullanmak için bu modülü kullanmak tercih ediliros.system()].

"Alt Fonksiyon Modülü ile Eski Fonksiyonların Değiştirilmesi"bölümünde altişlem Belgelerin bazı yararlı tarifleri olabilir.

Resmi belgeler altişlem modülü:


3504
2017-09-18 01:39



Değişken ikame kullanmanın bir yolu var mı? IE yapmaya çalıştım echo $PATH kullanarak call(["echo", "$PATH"])ama sadece harf dizisini tekrarladı $PATH herhangi bir ikame yapmak yerine. PATH ortam değişkeni alabileceğimi biliyorum, ama komutun aynen bash'ta uygulamış gibi davranmasını kolay bir yol olup olmadığını merak ediyorum. - Kevin Wheeler
@KevinWheeler Kullanmanız gerekecek shell=True Bunun için çalışmak için. - SethMMorton
@KevinWheeler KULLANMAMALIDIR shell=True, bu amaçla Python ile birlikte geliyor os.path.expandvars. Senin durumunda yazabilirsiniz: os.path.expandvars("$PATH"). @SethMMorton lütfen yorumunuzu tekrar gözden geçirin -> Neden kabuk = True kullanılmıyor? - Murmel
Python 3.5'den itibaren kullanmanız önerilir subprocess.run yerine subprocess.call. docs.python.org/3/library/subprocess.html - Hannes Karppila
Örnek çağrılar ls -l ama çıkışına erişim sağlamaz (stdout ulaşılabilir değil). Bunu kafa karıştırıcı buluyorum - bunun yerine, stdout olmadan bir komutu kullanabilirsiniz. touch. - florisla


Burada, harici programları ve her birinin avantajlarını ve dezavantajlarını arama yollarının bir özeti:

  1. os.system("some_command with args") komut ve argümanlarını sisteminizin kabuğuna geçirir. Bu güzel çünkü birden fazla komutu aynı anda çalıştırabilir ve boruları ve giriş / çıkış 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 karakterlerinin kaçmasını elle yapmanız gerekir. Diğer taraftan, bu, yalnızca kabuk komutları olan ve aslında harici programlar olmayan komutları çalıştırmanızı sağlar. Görmek Dökümantasyon.

  2. stream = os.popen("some_command with args") aynı şeyi yapacak os.system Bu işlem için standart giriş / çıkışa erişmek için kullanabileceğiniz dosya benzeri bir nesne vermesi dışında. Tümü, i / o'yu biraz farklı şekilde işleyen 3 diğer pop varyantı vardır. Her şeyi bir dize olarak iletirseniz, komutunuz kabuğa aktarılır; Onları bir liste olarak iletirseniz, bir şeyden kaçmak için endişelenmenize gerek yoktur. Görmek Dökümantasyon.

  3. Popen sınıf subprocess modülü. Bu bir yedek olarak tasarlanmıştır os.popen ama bu kadar kapsamlı olmasından dolayı biraz daha karmaşık olmanın dezavantajı var. Örneğin şunu söyleyiniz:

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

    yerine:

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

    ancak tüm seçeneklerin 4 farklı popen işlevi yerine bir birleşik sınıfta olması güzel bir şey. Görmek Dökümantasyon.

  4. call işlevinden subprocess modülü. Bu temelde tıpkı Popen Sınıfı ve aynı argümanları alır, ancak komut tamamlanana ve size geri dönüş kodunu verene kadar bekler. Örneğin:

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

    Görmek Dökümantasyon.

  5. Python 3.5 veya daha yeniyseniz, yeni kullanabilirsiniz subprocess.run Yukarıdaki gibi çok ama aynı zamanda daha esnek ve bir işlev döndürür CompletedProcess Komutun çalışmasını bitirdiğinde nesne.

  6. Os modülü ayrıca bir C programında sahip olduğunuz tüm fork / exec / spawn işlevlerine sahiptir, ancak bunları doğrudan kullanmanızı önermem.

subprocess modül muhtemelen kullandığınız şey olmalıdır.

Son olarak, kabuk tarafından bir sonda olarak çalıştırılacak son komutu ilettiğiniz tüm yöntemlerde, sizden kaçmaktan sorumlu olduğunuzu lütfen unutmayın. Ciddi güvenlik etkileri vardır Geçtiğiniz dizenin herhangi bir parçası tamamen güvenilir olmayabilir. Örneğin, bir kullanıcı dizgenin bir kısmını / bir kısmını giriyorsa. Emin değilseniz, bu yöntemleri sadece sabitlerle kullanın. Bu kodu dikkate alacağınız bir ipucu vermek için:

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

ve kullanıcının "annem beni sevmediğini & rm -rf /" yazdığını hayal edin.


2469
2017-09-18 13:11



Güzel cevap / açıklama. Bu cevap, Python'un bu makalede anlatılan sloganını nasıl doğrulamaktadır? fastcompany.com/3026446/...  "Stilistik, Perl ve Python'un farklı felsefeleri var. Perl’in en iyi bilinen sloganı" Bunu Yapmanın Birden Çok Yolu Vardır. "Python bunu yapmanın bariz bir yolu olacak şekilde tasarlanmıştır" Göründüğü gibi başka bir yol olmalı! Perl'de bir komutu yürütmek için sadece iki yolu biliyorum - open. - Jean
Python 3.5+ kullanıyorsanız, kullanın subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run - phoenix
Tipik olarak bilmesi gereken şey, çocuk sürecinin STDOUT ve STDERR ile ne yapıldığının bilinmemesidir, çünkü göz ardı edilirse, bazı (oldukça yaygın) koşullar altında, çocuk süreçleri sonunda STDOUT'a (STDERR) yazmak için bir sistem çağrısı yaparlar. Bu, işletim sistemi tarafından işlem için sağlanan çıktı arabelleğini aşacak ve İşletim Sistemi, bir işlem bu tampondan okuyana kadar engellenmesine neden olacaktır. Yani, şu anda önerilen yollarla, subprocess.run(..), tam olarak ne yapar "Bu, stdout'u veya stderr'i varsayılan olarak yakalamıyor." ima etmek? Ne dersin subprocess.check_output(..) ve STDERR? - Evgeni Sergeev
Komutlarımdan hangisini komut satırımı engellerim? yani eğer birden fazla komutu bir for loop python betiğimi engellemeden nasıl yapabilirim? Komutun çıktısını umurumda değil sadece bir sürü çalıştırmak istiyorum. - Charlie Parker
@ phoenix katılmıyorum. Python3'te os.system kullanımını engellemeniz için hiçbir şey yoktur. docs.python.org/3/library/os.html#os.system - Qback


Genellikle kullanırım:

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

İle istediğini yapmakta özgürsün stdout borudaki veriler. Aslında, bu parametreleri basitçe atlayabilirsiniz.stdout= ve stderr=) ve böyle davranacak os.system().


257
2017-09-18 18:20



.readlines() okur herşey Bir kerede hatlar, yani alt-işlem çıkana kadar bloke eder (borunun ucunu kapatır). Gerçek zamanlı olarak okumak için (eğer tamponlama sorunu yoksa): for line in iter(p.stdout.readline, ''): print line, - jfs
"Tamponlama sorunu olmazsa" ile ne demek istediğimi detaylandırır mısınız? İşlem kesinlikle engellenirse, alt işlem çağrısı da engellenir. Aynısı orijinal örneğimle de olabilirdi. Tamponlama ile ilgili olarak başka ne olabilir? - EmmEff
alt işlem, satır arabelleğe alma yerine etkileşimli olmayan modda blok tamponlamayı kullanabilir. p.stdout.readline()(not: hayır s Sonuçta, çocuk tamponunu dolduruncaya kadar hiçbir veri görmez. Çocuğunuz fazla veri üretmiyorsa, çıktı gerçek zamanlı olmayacaktır. İçindeki ikinci sebebi görün S: Neden sadece bir boru (popen ()) kullanmıyorsunuz?. Bazı geçici çözümler sağlanmıştır bu cevapta (pexpect, pty, stdbuf) - jfs
arabelleğe alma sorunu yalnızca gerçek zamanda çıktı almak istediğinizde ve hiçbir şey yazdırmayan kodunuza uygulanmazsa önemlidir herşey veri alındı - jfs


Çocuğun sürecini çağırandan ayırma ile ilgili bazı ipuçları (çocuk sürecini arka planda başlatır).

Bir CGI komut dosyasından uzun bir görev başlatmak istediğinizi varsayalım, bu, çocuk işleminin CGI kod yürütme işleminden daha uzun bir süre yaşaması gerekir.

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 tamamlanana kadar "altprocess" satırında beklemek istememenizdir. Ancak, buradaki örnekten 'biraz daha fazla kod' sonra ne olduğu net değil.

Hedef platformum freebsd, ancak geliştirme pencerelerde oldu, bu yüzden ilk önce pencerede problemle karşılaştım.

Pencerelerde (xp kazanmak), longtask.py çalışmayı bitirene kadar ana işlem bitmez. CGI-scriptinde istediğin şey bu değil. Sorun Python'a özgü değildir, PHP topluluğunda problemler aynıdır.

Çözüm, DETACHED_PROCESS ürününü geçmek Süreç Yaratma Bayrağı win API'daki temel CreateProcess işlevine. Eğer pywin32'yi kurduysanız, bayrağı win32process modülünden alabilirsiniz, aksi takdirde bunu kendiniz tanımlamanız gerekir:

DETACHED_PROCESS = 0x00000008

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

/ * UPD 2015.10.27 notlar altında bir yorum @eryksun, semantically doğru bayrağı CREATE_NEW_CONSOLE olduğunu (0x00000010) * /

Freebsd'de başka bir sorunumuz var: ana işlem bittiğinde, çocuk süreçlerini de tamamlıyor. Ve bu da CGI-scriptinde istediğin şey değil. Bazı deneyler, sorunun sys.stdout paylaşımında olduğunu gösterdi. Ve çalışma çözümü şu oldu:

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

Diğer platformlarda kodu kontrol etmedim ve freebsd üzerindeki davranışların nedenlerini bilmiyorum. Eğer birileri biliyorsa, fikirlerinizi paylaşın. Python'daki arkaplan işlemlerinin başlatılması için googling henüz bir ışık tutmuyor.


158
2018-02-12 10:15



Pydev + eclipse içinde py2exe uygulamaları geliştirerek olası bir "quirk" fark ettim. Eclipse'in çıkış penceresi sona ermediği için ana komut dosyasının ayrılmamış olduğunu söyleyebildim; komut dosyası tamamlanmaya devam ederse bile hala geri dönüş bekliyor. ancak, bir py2exe çalıştırılabilirliğine derlemeye çalıştığımda, beklenen davranış gerçekleşir (süreçleri ayrılır, sonra çıkar). Emin değilim, ama yürütülebilir adı artık işlem listesinde yok. Bu tüm yaklaşımlar için çalışır (os.system ("start *"), oss.P_DETACH ile os.spawnl, altprogramlar, vb.) - maranas
Windows gotcha: Her ne kadar Python daemon'umu öldürdüğümde, DETACHED_PROCESS ile bir süreç oluşturmuş olmama rağmen, tüm açılmış süreçler sona erene kadar tüm portlar açıldı. WScript.Shell tüm sorunlarımı çözdü. Burada örnek: pastebin.com/xGmuvwSx - Alexey Lebedev
CREATE_NEW_PROCESS_GROUP bayrağına da ihtiyacınız olabilir. Görmek Çocuğun sonlandırması durumunda bile çocuk sürecini beklemek - jfs
Aşağıdakiler yanlıştır: "[o] n windows (win xp), ana işlem longtask.py çalışmasını bitirinceye kadar tamamlanmayacaktır". Üst öğe normal olarak çıkacaktır, ancak konsol penceresi (conhost.exe örneği) yalnızca son eklenen işlemden çıktığında kapanır ve alt öğe üst konsolun konsolide kalmasına neden olabilir. Ayar DETACHED_PROCESS içinde creationflags çocuğun devralmasını veya bir konsol oluşturmasını engelleyerek bunu önler. Bunun yerine yeni bir konsol istiyorsanız, kullanın CREATE_NEW_CONSOLE (0x00000010). - eryksun
Ayrılmış bir süreç olarak yürütmenin yanlış olduğunu kastetmedim. Bu, standart tutamaçları dosyalara, borulara veya os.devnull Bazı konsol programları, aksi halde bir hata ile çıktığı için. Alt işlemin, kullanıcıyla ana işlemle eş zamanlı olarak etkileşim kurmasını istediğinizde yeni bir konsol oluşturun. Her ikisini de tek bir pencerede yapmayı denemek kafa karıştırıcı olurdu. - eryksun


Eğer sizin için kabuk kaçınıyor ve bu nedenle çok daha güvenli olduğundan os.system yerine alt işlem modülünü kullanmanızı tavsiye ederim: http://docs.python.org/library/subprocess.html

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

98
2017-09-18 01:42





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

Komutun sonuçlarını döndürmek isterseniz, kullanabilirsiniz os.popen. Ancak, bu sürüm 2.6'dan beri kullanımdan kaldırılmıştır. alt işlem modülüDiğer cevaplar iyi karşılandı.


94
2017-09-18 01:37



popen kullanımdan kaldırıldı lehine altişlem. - Fox Wilson
Ayrıca os.system çağrısı ile sonucunuzu da kaydedebilirsiniz, çünkü örneğin os.system ('ls -l> test2.txt') gibi UNIX kabuğunun kendisi gibi çalışır - Stefan Gruenwald


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ümanlar için google'a bırakıyorum. Benzer şeyler yapacak bir dizi işlev (exec * ve spawn *) vardır.


84
2017-09-18 01:37



Ne demek istiyorsunuz "komut temizlenmedi"? - Peter Mortensen
Neredeyse yaklaşık on yıl önce ne kastettiğimi bilmiyorum (tarihi kontrol edin!), Ama tahmin etmem gerekirse, doğrulama yapılmaması olurdu. - nimish