Python'da Bash komutlarını çalıştırma


299

Yerel makinemde, bu satırı içeren bir python betiği çalıştırıyorum

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)

Bu iyi çalışıyor.

Sonra aynı kodu bir sunucuda çalıştırın ve aşağıdaki hata iletisini alıyorum

'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import  diag
ImportError: No module named swap

O zaman yaptığım şey, print bashCommandonu çalıştırmadan önce beni terminaldeki komuttan daha fazla basan bir os.system().

Tabii ki, yine hatayı alıyorum (neden olduğu os.system(bashCommand)) ama bu hatadan önce terminaldeki komutu yazdırıyor. Sonra bu çıktıyı kopyaladım ve bir kopyasını terminale yaptım ve enter'a bastım ve işe yarıyor ...

Neler olup bittiğine dair bir ipucu var mı?


2
Nasıl koştuğunuza bağlı olarak ortamda bir fark var gibi görünüyor cwm. Belki de .bashrcinteraktif bash kullanımı için ortamı ayarlayan bazı yapılandırmalarınız var ?
Sven Marnach

Sunucuda oturum açtığınızda komutu komut satırından çalıştırmayı denediniz mi? Gönderiniz sadece "terminale yapıştırdığınız" yazıyor.
Sven Marnach

@Sven: evet Komutu doğrudan sunucunun terminalinde çalıştırdığım anlamına geliyordu
mkn

PYTHONPATH'da nasıl koştuğunuza bağlı olarak bir fark var gibi görünüyor cwm. Ya da belki PATH'de bir fark vardır ve farklı versiyonu cwmdenir. Veya Python'un farklı versiyonları. Makineye erişim olmadan bunu anlamak gerçekten zor ...
Sven Marnach

Yanıtlar:


314

Kullanma os.system. Alt süreç lehine onaylanmamıştır . Gönderen docs : ": Bu modül eski birkaç modül ve fonksiyonlarını değiştirmek niyetinde os.system, os.spawn".

Sizin durumunuzda olduğu gibi:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()

8
Bu cd 'path\to\somewhere', bir yerde çalıştırılması gereken başka bir bash komutunu takip etmem gerektiğinde istediğim şeyi yapmadı . @ user225312
AWrightIV

36
@AWrightIV Alt işleminizin belirli bir çalışma dizininde çalıştırılması gerekiyorsa, cwdPopen argümanı kullanabilirsiniz :subprocess.Popen(..., cwd='path\to\somewhere')
su geçirmez

7
Komuta için burada olduğu gibi shell = True gerekiyordu; stackoverflow.com/questions/18962785/…
user984003

4
Bu durumda shlex.split () yerine string.split () kullanın
Alexey Sviridov

4
... ( stdout=filebu durumda çıktıyı bir dosyaya yönlendirir. Uygular > file). ..., '>', 'file']Yönlendirmeyi bekleyen son komutu iletmek yanlış olur (kabuk olmadan çalışmaz ve bir kabuk kullanırsanız, komutu dize olarak
geçirmeniz

186

Buradaki önceki yanıtları biraz genişletmek için, genellikle gözden kaçan bazı ayrıntılar vardır.

  • Tercih subprocess.run()üzerinde subprocess.check_call()üzerinde ve arkadaşlar subprocess.call()üzerinde subprocess.Popen()üzerinde os.system()üzerindeos.popen()
  • Anlayın ve muhtemelen kullanın text=True, aka universal_newlines=True.
  • Teklifin anlamını shell=Trueveya shell=Falsenasıl değiştiğini ve kabuk kolaylıklarının kullanılabilirliğini anlayın .
  • shVe Bash arasındaki farkları anlama
  • Bir alt işlemin üst öğeden nasıl ayrı olduğunu ve genellikle üst öğeyi değiştiremediğini anlayın.
  • Python yorumlayıcısını Python'un bir alt süreci olarak çalıştırmaktan kaçının.

Bu konular aşağıda daha ayrıntılı olarak ele alınmaktadır.

Tercih subprocess.run()veyasubprocess.check_call()

subprocess.Popen()Fonksiyon düşük seviye beygir ancak doğru kullanımı zor ve rahatlıkla zaten çeşitli amaçlar için fonksiyonları sarıcı üst düzeyde bir dizi gibi standart kütüphanesinde bulunması kod birden fazla satır ... yapıştırarak / kopyalama sona, bunlar aşağıda daha ayrıntılı olarak sunulmuştur.

İşte belgelerden bir paragraf :

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

Ne yazık ki, bu sarmalayıcı işlevlerinin kullanılabilirliği Python sürümleri arasında farklılık gösterir.

  • subprocess.run()Python 3.5'te resmen tanıtıldı. Aşağıdakilerin tümünü değiştirmek içindir.
  • subprocess.check_output()Python 2.7 / 3.1'de tanıtıldı. Temel olaraksubprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
  • subprocess.check_call()Python 2.5'te tanıtıldı. Temel olaraksubprocess.run(..., check=True)
  • subprocess.call()Python 2.4'te orijinal subprocessmodülde ( PEP-324 ) tanıtıldı . Temel olaraksubprocess.run(...).returncode

Yüksek seviye API vs subprocess.Popen()

Yeniden düzenlenmiş ve genişletilmiş subprocess.run(), yerini aldığı eski eski işlevlerden daha mantıklı ve çok yönlüdür. CompletedProcessBitmiş alt işlemden çıkış durumunu, standart çıktıyı ve diğer birkaç sonucu ve durum göstergesini almanıza izin veren çeşitli yöntemlere sahip bir nesne döndürür .

subprocess.run()kontrolü çalıştırmak ve Python'a geri göndermek için bir programa ihtiyacınız varsa gitmenin yoludur. Daha fazla ilgili senaryolar için (arka plan süreçleri, belki de Python üst programı ile etkileşimli G / Ç ile) hala subprocess.Popen()tüm tesisatları kendiniz kullanmanız ve bunlarla ilgilenmeniz gerekir . Bu, tüm hareketli parçaların oldukça karmaşık bir şekilde anlaşılmasını gerektirir ve hafife alınmamalıdır. Daha basit Popennesne , alt işlemin kalan süresi boyunca kodunuzdan yönetilmesi gereken (muhtemelen hala çalışıyor) işlemi temsil eder.

Belki de subprocess.Popen()sadece bir süreç yarattığı vurgulanmalıdır . Eğer bunu bırakırsanız, Python ile eşzamanlı olarak çalışan bir alt işleminiz olur, böylece bir "arka plan" işlemi gerçekleşir. Girdi veya çıktı yapması veya sizinle başka bir şekilde koordinasyon yapması gerekmiyorsa, Python programınıza paralel olarak faydalı işler yapabilir.

Kaçının os.system()veos.popen()

Sonsuz zamandan beri (iyi, Python 2.5 beri) osmodülü belgelerine tercih öneri içeriyordu etmiştir subprocessüzerinde 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 kullanmak için tercih edilir.

Sorunları, system()sisteme bağlı olduğu ve alt süreçle etkileşime geçmenin yolları sunmadığıdır. Python'un erişemeyeceği standart çıkış ve standart hata ile çalışır. Python'un geri aldığı tek bilgi, komutun çıkış durumudur (sıfır, başarı anlamına gelir, ancak sıfır olmayan değerlerin anlamı da sisteme bağımlıdır).

PEP-324 (daha önce bahsedilmişti), neden os.systemsorunlu olduğu ve subprocessbu sorunları nasıl çözme girişimleri için daha ayrıntılı bir gerekçe içeriyor .

os.popen()eskiden daha güçlü bir şekilde cesareti kırılmıştı :

2.6 sürümünden beri kullanımdan kaldırıldı : Bu işlev kullanılmıyor. subprocessModülü kullanın .

Bununla birlikte, Python 3'te bir zamandan beri, basitçe kullanmak için yeniden uygulandı subprocessve subprocess.Popen()ayrıntılar için belgelere yönlendirildi .

Anlayın ve genellikle kullanın check=True

subprocess.call()Aynı sınırlamaların çoğuna sahip olduğunu da fark edeceksiniz os.system(). Düzenli kullanımda, genellikle sürecin başarılı bir şekilde tamamlanıp tamamlanmadığını kontrol etmelisiniz subprocess.check_call()ve hangisi subprocess.check_output()(burada ikinci aşama da bitmiş alt sürecin standart çıktısını döndürür). Benzer şekilde, alt işlemin bir hata durumu döndürmesine özellikle izin vermeniz gerekmedikçe genellikle check=Trueile birlikte kullanmalısınız subprocess.run().

Uygulamada, check=Trueveya subprocess.check_*ile Python , alt işlem sıfır olmayan bir çıkış durumu döndürürse bir CalledProcessErroristisna atar .

İle ortak bir hata , alt işlem başarısız olursa, aşağı akış kodu başarısız olduğunda subprocess.run()atlamak check=Trueve şaşırtmaktır.

Öte yandan, ortak bir sorun check_call()ve check_output()istisnası örneğin yükseltildi zaman gözü kapalı bu işlevleri kullanılan kullanıcılar şaşırdık olmasıydı grepbir maç bulamadık. (Muhtemelen grepaşağıda açıklandığı gibi yerel Python koduyla değiştirmelisiniz .)

Her şey sayılır, kabuk komutlarının bir çıkış kodunu nasıl döndürdüğünü ve hangi koşullar altında sıfırdan farklı (hata) bir çıkış kodu döndüreceklerini anlamanız ve tam olarak nasıl işlenmesi gerektiğine dair bilinçli bir karar vermeniz gerekir.

Anlayın ve muhtemelen text=Trueaka kullanınuniversal_newlines=True

Python 3'ten beri, Python'un içindeki dizeler Unicode dizeleridir. Ancak bir alt işlemin Unicode çıktısı veya dizeleri oluşturduğunun garantisi yoktur.

(Farklılıklar hemen belli değilse, Ned Batchelder'in Pragmatic Unicode'u , açıkça zorunlu değilse, okuma önerilir. İsterseniz bağlantıyı arkasında 36 dakikalık bir video sunumu olsa da, sayfayı okumak kendiniz önemli ölçüde daha az zaman alacaktır. )

Derinlerde, Python bir bytestampon getirmeli ve bir şekilde yorumlamalıdır. O ikili verilerin bir damla içeriyorsa, bu olmamalı bu hataya açık ve hata neden olan davranış, çünkü Unicode dizesine deşifre edilmesi - Birçok Python 2 komut kalbura sinir bozucu davranışının hassas tür bir yolu yoktu önce kodlanmış metin ve ikili veriler arasında doğru bir şekilde ayrım yapın.

İle text=True, Python'a, aslında, sistemin varsayılan kodlamasında metinsel verileri beklediğinizi ve Python'un yeteneğinin en iyisi olan bir Python (Unicode) dizgisine kodunun çözülmesi gerektiğini söylersiniz (genellikle herhangi bir ortama kadar UTF-8) tarih sistemi, belki Windows hariç?)

Geri talep ettiğiniz şey bu değilse , Python size ve dizelerinde sadece bytesdizeler verecektir . Belki bazı daha sonra işaret yok onlar metin dizeleri sonuçta olduklarını biliyoruz ve onların kodlama biliyorum. Sonra bunları deşifre edebilirsiniz.stdoutstderr

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

Python 3.7, daha textönce biraz yanıltıcı olarak adlandırılan anahtar kelime argümanı için daha kısa ve daha açıklayıcı ve anlaşılır takma adı tanıttı universal_newlines.

Anlamak shell=Truevsshell=False

İle shell=Truesize sizin kabuğuna tek dizesi geçirmek ve kabuk oradan alır.

İle shell=Falsesize kabuk atlayarak OS bağımsız değişkenlerin bir listesini geçmektedir.

Bir kabuğunuz yoksa, bir işlemi kaydedersiniz ve hata veya hatta güvenlik sorunları barındırabilen veya barındırmayan oldukça önemli miktarda gizli karmaşıklıktan kurtulursunuz .

Öte yandan, bir kabuğunuz yoksa, yeniden yönlendirme, joker karakter genişletmesi, iş kontrolü ve çok sayıda diğer kabuk özelliğiniz yoktur.

Yaygın bir hata, shell=TruePython'u bir jeton listesi kullanmak ve yine de iletmektir. Bu bazı durumlarda işe yarar, ancak gerçekten kötü tanımlanmış ve ilginç şekillerde kırılabilir.

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

Hangi koşullar altında çalışmayı durdurabileceğini tam olarak anlamadığınız sürece ortak imbik "ama benim için çalışıyor" yararlı bir çürütme değil.

Yeniden Düzenleme Örneği

Çoğu zaman, kabuğun özellikleri yerel Python kodu ile değiştirilebilir. Basit Awk veya sedkomut dosyaları muhtemelen Python'a çevrilmelidir.

Bunu kısmen göstermek için, burada birçok kabuk özelliği içeren tipik ama biraz aptalca bir örnek var.

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'round-trip min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

Burada dikkat edilmesi gereken bazı noktalar:

  • İle shell=Falsekabuk dizeleri etrafında gerektirdiğini size alıntı gerekmez. Zaten tırnak koymak muhtemelen bir hatadır.
  • Bir alt işlemde mümkün olduğunca az kod çalıştırmak genellikle mantıklıdır. Bu size Python kodunuzdan yürütme üzerinde daha fazla kontrol sağlar.
  • Bunu söyledikten sonra, karmaşık kabuk boru hatları sıkıcıdır ve bazen Python'da yeniden uygulanması zorlaşır.

Yeniden düzenlenmiş kod ayrıca kabuğun çok kısa bir sözdizimi ile sizin için ne kadar başarılı olduğunu da gösterir - daha iyi veya daha kötü. Python diyor örtülü daha iyidir açık ama Python kodu olan oldukça ayrıntılı ve belki bu gerçekten olduğundan daha karmaşık görünüyor. Öte yandan, kabuk komut çıktısı ile birlikte ana bilgisayar adını kolayca ekleyebileceğimiz geliştirme ile önemsiz bir şekilde örneklendiği gibi, başka bir şeyin ortasında kontrol sahibi olabileceğiniz bir dizi nokta sunar. (Bu hiçbir şekilde kabukta yapmak zor değildir, ama yine de başka bir saptırma ve belki de başka bir süreç pahasına.)

Ortak Kabuk Yapılar

Tamlık için, bu kabuk özelliklerinden bazılarının kısa açıklamaları ve bunların yerel Python olanaklarıyla nasıl değiştirilebileceğine dair bazı notlar.

  • Globbing olarak adlandırılan joker karakter genişletmesi, glob.glob()basit Python dizesi karşılaştırmalarıyla veya çok sık olarak değiştirilebilir for file in os.listdir('.'): if not file.endswith('.png'): continue. Bash, .{png,jpg}parantez genişletme ve {1..100}tilde genişletme gibi çeşitli genişletme olanaklarına sahiptir ( ~ana dizininize ve daha genel ~accountolarak başka bir kullanıcının ana dizinine genişler )
  • Kabuk değişkenleri gibi $SHELLveya $my_exported_varbazen Python değişkenleri ile değiştirilebilir. Örneğin olarak dışa kabuk değişkenleri mevcuttur os.environ['SHELL'](anlamı exportsubprocesses değişken kullanılabilir olmasını sağlamaktır -. Açıkça Python kabuğun alt işlemi ya da tam tersi olarak çalışan mevcut olmayacaktır subprocesses kullanılamaz bir değişken env=kelime subprocessyöntemlere argüman , alt işlem ortamını sözlük olarak tanımlamanızı sağlar, bu nedenle Python değişkenini bir alt işlem için görünür hale getirmenin bir yolu budur). İle shell=Falseherhangi bir tırnak kaldırmak için nasıl anlamak gerekir; örneğin, dizin adı etrafında tırnak işaretleri olmadan cd "$HOME"eşdeğerdir os.chdir(os.environ['HOME']). (Çok sıkcdyine de yararlı veya gerekli değildir ve birçok yeni başlayan değişkenin etrafındaki çift tırnak işaretlerini atlar ve bir güne kadar ondan uzaklaşır ... )
  • Yeniden yönlendirme, bir dosyadan standart girdiniz olarak okumanıza ve standart çıktınızı bir dosyaya yazmanıza olanak tanır. grep 'foo' <inputfile >outputfileAçılan outputfileyazma ve inputfileokuma ve standart girdi olarak içeriğini geçer grepolan standart çıktı daha sonra topraklarda, outputfile. Bunun yerine yerel Python kodu ile değiştirilmesi genellikle zor değildir.
  • Boru hatları bir yönlendirme şeklidir. echo foo | nlstandart çıktısının echostandart girdi olduğu iki alt işlem çalıştırır nl(işletim sistemi düzeyinde, Unix benzeri sistemlerde, bu tek bir dosya tanıtıcısıdır). Boru hattının bir veya iki ucunu yerel Python kodu ile değiştiremiyorsanız, sonuçta özellikle bir kabuk kullanmanın iki veya üçten fazla işlemi varsa ( pipesPython standart kütüphanesindeki modüle veya bir sayıya bakın) daha modern ve çok yönlü üçüncü taraf rakiplerden).
  • İş kontrolü, işleri kesmenize, arka planda çalıştırmanıza, ön plana döndürmenize vb. Olanak tanır. Bir işlemi durdurmak ve devam ettirmek için temel Unix sinyalleri elbette Python'dan da temin edilebilir. Ancak işler, Python'dan böyle bir şey yapmak isteyip istemediğinizi anlamak zorunda olduğunuz süreç gruplarını vb.İçleyen kabukta daha üst düzey bir soyutlamadır.
  • Kabukta alıntı yapmak, her şeyin temelde bir dize olduğunu anlayana kadar potansiyel olarak kafa karıştırıcıdır . Buna ls -l /eşdeğerdir, 'ls' '-l' '/'ancak değişmez değerler arasında alıntı yapmak tamamen isteğe bağlıdır. Kabuk meta karakterleri içeren tırnaksız dizeler parametre genişletmesi, boşluk belirteci ve joker karakter genişletmesi geçirir; çift ​​tırnak, boşluk belirtecini ve joker karakter genişlemesini engeller, ancak parametre genişletmelerine izin verir (değişken değiştirme, komut değiştirme ve ters eğik çizgi işleme). Bu teoride basittir, ancak özellikle birkaç yorum katmanı olduğunda (örneğin bir uzak kabuk komutu) şaşırtıcı olabilir.

shVe Bash arasındaki farkları anlama

subprocess/bin/shözellikle başka bir şekilde talep etmediğiniz sürece kabuk komutlarınızı çalıştırır (tabii ki COMSPECdeğişkenin değerini kullandığı Windows'ta ). O Bu araçlar çeşitli Bash okunur diziler gibi özellikler, [[vb kullanılamaz.

Yalnızca Bash sözdizimini kullanmanız gerekiyorsa, kabuğa giden yolu şu şekilde aktarabilirsiniz executable='/bin/bash'(elbette Bash başka bir yere kuruluysa, yolu ayarlamanız gerekir).

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

A subprocess, üst öğesinden ayrıdır ve değiştirilemez

Biraz yaygın bir hata,

subprocess.run('foo=bar', shell=True)
subprocess.run('echo "$foo"', shell=True)  # Doesn't work

zerafet eksikliğinin yanı sıra, "alt süreç" adının "alt" kısmının anlaşılmasında da temel bir eksikliğe ihanet eder.

Bir alt süreç Python'dan tamamen ayrı çalışır ve bittiğinde, Python'un ne yaptığına dair hiçbir fikri yoktur (çıkış durumundan ve alt süreçten çıktından çıkarabileceği belirsiz göstergelerin dışında). Çocuk genellikle ebeveynin çevresini değiştiremez; bir değişken ayarlayamaz, çalışma dizinini değiştiremez veya pek çok kelimeyle, üst öğeden işbirliği olmadan üst öğesiyle iletişim kuramaz.

Bu özel durumda acil düzeltme, her iki komutu tek bir alt işlemde çalıştırmaktır;

subprocess.run('foo=bar; echo "$foo"', shell=True)

açıkçası bu özel kullanım durumu kabuk gerektirmez. Unutmayın, mevcut sürecin ortamını (ve böylece çocuklarını)

os.environ['foo'] = 'bar'

veya bir ortam ayarını

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(bariz yeniden düzenlemeden bahsetmiyorum subprocess.run(['echo', 'bar']); ama echoelbette bir alt süreçte çalıştırılacak bir şeyin kötü bir örneğidir).

Python'u Python'dan çalıştırmayın

Bu biraz şüpheli bir tavsiye; kesinlikle Python yorumlayıcısını bir Python betiğinden bir alt işlem olarak çalıştırmanın mantıklı olduğu veya hatta mutlak bir gereklilik olduğu durumlar vardır. Ancak çok sık, doğru yaklaşım sadece importdiğer Python modülüne çağrı kodunuza girer ve işlevlerini doğrudan çağırır.

Diğer Python betiği kontrolünüz altındaysa ve bir modül değilse, bir tanesine dönüştürmeyi düşünün . (Bu cevap zaten çok uzun, bu yüzden burada ayrıntılara girmeyeceğim.)

Paralelliğe ihtiyacınız varsa, Python işlevlerini alt işlemlerde multiprocessingmodülle çalıştırabilirsiniz. threadingTek bir işlemde birden çok görevi yürüten de vardır (bu daha hafiftir ve size daha fazla kontrol sağlar, ancak aynı zamanda bir işlem içindeki iş parçacıklarının sıkıca bağlı ve tek bir GIL'ye bağlı olmasıyla daha kısıtlıdır .)


2
Python'u alt işlem olarak çağırmaktan nasıl kaçınabileceğinizle ilgili daha ayrıntılı bir açıklama için, teğet olarak benzer bir soru
tripleee

4
Komuta sorudan deyimin nasıl çalıştırılacağını göstermek için böylesine temel bir soruya yeni bir cevap göndermek zorunda olduğumu aklıma getiriyor. Cevabınız uzun ama böyle bir örnek göremiyorum. İlgisiz: kargo ile iletişimden kaçının. Check_call () sizin durumunuzda çalışıyorsa kullanın. run()Körü körüne kullanılan bir kodu düzeltmek zorunda kaldım . Kayıp check=True, check_call kullanılırsa önlenecek bir hataya neden oldu - "check" adındaysa, kaybedemezsiniz - doğru varsayılan budur: hataları sessizce yok saymayın. Daha fazla okumadım.
jfs

1
@jfs Geri bildiriminiz için teşekkür ederiz, aslında Bash vs hakkında bir bölüm eklemeyi planlıyordum shama beni yendiniz . Bu tuzakların belli olmadığı yeni başlayanlara yardımcı olmak için yeterince ayrıntıya girmeye çalışıyorum, bu yüzden biraz uzun soluklu oluyor. Aksi takdirde sizinki yeterli olmalıdır; +1
tripleee

stderr/stdout = subprocess.PIPEVarsayılan ayarlardan daha yüksek performans yükü var mı ?
Stringers

1
@Stringers Test etmedim, ama neden olması gerektiğini anlamıyorum. Bu boruları biraz işlem yapan bir şeye bağlarsanız, elbette işlemenin hesaplanması gerekir; ancak borunun kendisinde olmaz. Varsayılan, stdout veya stderr'i hiç yakalamamaktır, yani yazdırılan her şey Python'un görünürlüğü ve kontrolü dışında olduğu gibi os.system().
tripleee

41

Alt işlemle çağırın

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

Aldığınız hata, sunucuda takas modülü olmadığı için görünüyor, sunucuya takas yüklemeniz ve komut dosyasını tekrar çalıştırmanız gerekir


3
swapKabuk eserlerden komutunu çalıştırarak çünkü modül, belli ki var.
Sven Marnach

2
Sunucuda değil, sunucuda çalıştırdığında bir alma hatası var.
Jakob Bowyer

@mkn: "Sonra bu çıktıyı kopyaladım ve bir kopyasını terminale yapıştırdım ve enter'a tıkladım ve işe yaradı ..." - Bunu sunucuda veya makinenizde denediniz mi?
Sven Marnach

Bunu tek başına bir bilgisayarda iyi mi çalıştırıyorsunuz, ancak sunucunuzda çalıştırdığınızda çalışmıyor mu? Yoksa bir sunucu terminalinde çalıştırabilir, ancak sunucunun kendisini değil
Jakob Bowyer

1
öyle yanlış kullanmak yoksa shell=Trueo zaman birden argümanlar yani geçmek için bir liste kullanmalısınız kullanmak ['a', 'b', 'c']yerine 'a b c'. Rağmen saf bir bölünme > filekomut (kabuk yeniden yönlendirme) nedeniyle çalışmaz . Daha fazla detay
jfs

18

Komutları yürütmek için -c parametresiyle bash programını kullanmanız mümkündür:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])

2
subprocess.check_output(bashCommand, shell=True)aynı şeyi yapar. Komutunuz statik bir dizeyse, kendiniz bir listeye ayrıştırmayı deneyin ve shell=True; yine de bu durumda yeniden yönlendirme için kabuk gerekir, ya da başka saf Python -with open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
üçlü

@ tripleee note: /bin/sh(alt işlem tarafından kullanılır) mutlaka bash(bashisms'i kullanamazsınız) değildir. Ancak executable='/bin/bashistenirse kullanabilirsiniz . İşte bir kod örneği
jfs

2
. komut başarıyla (kabul edilen ve 2 popüler cevaplar sadece yanlış Küçük bir kelime oyunu başlamalıdır İlk yanıtım: check_output()(çıkış dolayı her zaman için burada işe yaramaz boş edilir > fileyönlendirme; kullanımını check_call(). Bunun yerine
jfs

16

Kullanabilirsin subprocess, ama her zaman bunun 'Pitonik' bir yol olmadığını hissettim. Bu yüzden komut satırı işlevlerini çalıştırmayı kolaylaştıran Sultan (utanmaz fiş) oluşturdum.

https://github.com/aeroxis/sultan


3
Aferin! Alt işlemden çok daha temiz ve daha sezgisel.
mjd2

Çok teşekkür ederim! Bunu duyduğuma sevindim!
David Daniel

2
Bu dürüstçe standart kütüphaneye uyarlanmalıdır.
Joshua Detwiler

1
Sultan'ı kullanarak terminalden çıktı almanın bir yolu var mı?
alvas

Evet @alvas yapabilirsiniz ... İşte bununla ilgili dokümanlar: sultan.readthedocs.io/en/latest/…
David Daniel

7

Hataya göre sunucuda takas adında bir paket eksik . Bu /usr/bin/cwmgerektirir. Ubuntu / Debian python-swapkullanıyorsanız, yetenek kullanarak yükleyin .


ama doğrudan terminalde çalıştırdığımda çalışır ... yani takas orada olmalı, değil mi?
mkn

iki seçenek vardır. ya bulamıyor swapya da ilk etapta ithal etmemeliydi. import swapelle yapabilir misin çalışıyor mu?
kichik

hm yapamam. Ben terminalde python yazarak python başlatmak ve sonra ithalat takas yazın sonra "ImportError: takas adında bir modül" hatası var. Garip şey hala cwm komutunu doğrudan sunucunun terminalinde çalıştırdığımda çalışıyor
mkn

sys.pathÇalıştığı yerde ve çalışmadığı yerde yazdırmayı deneyin . Ardından takas klasörünü veya yazdırılan klasörlerde swap.py dosyasını aramayı deneyin. Sven'in dediği gibi, bu yollarla ilgili bir sorun olabilir ve bu, onu bulmanıza yardımcı olacaktır.
kichik

4

Ayrıca 'os.popen' kullanabilirsiniz. Misal:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

Çıktı:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None

1
Dokümantasyon büyük bir kırmızı kutu içeriyor: " 2.6 sürümünden bu yana kullanımdan kaldırıldı : Bu işlev kullanılmıyor. subprocessModülü kullanın ."
tripleee

1
Adil olmak gerekirse, os.popenartık bu uyarıya sahip değildir ve şu an sadece ince bir sargıdır subprocess.Popen().
üçlü 3

4

Komutu kabuk olmadan çalıştırmak için, komutu liste olarak iletin ve aşağıdakileri kullanarak Python'da yeniden yönlendirmeyi uygulayın [subprocess]:

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

Not: > test.ntSonunda hayır . stdout=fileyönlendirmeyi uygular.


Komutu Python'daki kabuğu kullanarak çalıştırmak için, komutu dize olarak iletin ve etkinleştirin shell=True:

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

Burada kabuk çıkış yönlendirmesinden sorumludur ( > test.ntkomuttadır).


Bashisms kullanan bir bash komutu çalıştırmak için bash yürütülebilir dosyasını açıkça belirtin, örn. Bash işlem ikamesini taklit etmek için :

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')

Belki de bu değil anma .split()dizeleri vb ayrı rutin vardır orada cinsindendir zaman yeterli değildir shlex.split()keyfi karmaşık kabuk söz dizimi ile baş edebiliyor.
tripleee

@tripleee .split()bu durumda çalışır. shlex.split()bazen yararlı olabilir, ancak bazı durumlarda da başarısız olabilir. Bahsedilebilecek çok şey var. Yukarıda verilen alt işlem etiketi açıklamasına bağlantı ile başlayabilirsiniz.
jfs

0

Bunu yapmanın pythonic yolu subprocess.Popen

subprocess.Popen ilk öğenin çalıştırılacak komut olduğu ve ardından komut satırı bağımsız değişkenlerinin olduğu bir liste alır.

Örnek olarak:

import subprocess

args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line

args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line

Hayır, son örnek, echo -v '"Hello Again!"'çift ​​tırnak işaretleri arasında tek tırnak işareti ile aynıdır .
tripleee

Ayrıca, doğru bir şekilde kullanmak için subprocesss.Popen, sonuçta elde edilen işlem nesnesini yönetmeniz gerekir (en azından, wait()bir zombi işlemine dönüşmesini önlemek için bir gerçekleştirin ).
üçlü 3
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.