Python'da çıktı alt işlemle nasıl yeniden yönlendirilir?


97

Komut satırında ne yapıyorum:

cat file1 file2 file3 > myfile

Python ile yapmak istediğim şey:

import subprocess, shlex
my_cmd = 'cat file1 file2 file3 > myfile'
args = shlex.split(my_cmd)
subprocess.call(args) # spits the output in the window i call my python program

Alt işlemde böyle bir komutu çalıştırmak size herhangi bir çıktı vermez. Onu > myfile cat file1 file2 file3'ten python'a yönlendirmeden çalıştırmak isteyebilir misiniz ?
PoltoS

@PoltoS Bazı dosyaları birleştirmek ve ardından ortaya çıkan dosyayı işlemek istiyorum. Kedi kullanmanın en kolay alternatif olduğunu düşündüm. Bunu yapmanın daha iyi / pitonik bir yolu var mı?
catatemypythoncode

os.sendfile()tabanlı çözüm mümkündür, bkz çoğaltmak Python unix kedi komutunu
jfs

1
Çıktı yeniden yönlendirmesinin ('>' veya '>>') alt işlemde çalışmadığını düşünüyorum.Popen (en azından Python 2.7'de) (kabuk = Gerçek kipte) Bu örnekte, diğerlerinin de belirttiği gibi, geçici olarak çalışabilirsiniz. bu, yeniden yönlendirme kullanmayarak, ancak diğer durumlarda yeniden yönlendirme yararlıdır. Alt işlemde yeniden yönlendirme veya borulama desteklenmiyorsa, Açma belgelenmelidir (ve / veya os.system () bu düzeltilene kadar kullanımdan kaldırılmamalıdır)
Ribo

Yanıtlar:


20

GÜNCELLEME: os.system, Python 3'te hala mevcut olsa da önerilmez.


Kullanım os.system:

os.system(my_cmd)

Alt işlemi gerçekten kullanmak istiyorsanız, işte çözüm (çoğunlukla alt işlem belgelerinden alınmıştır):

p = subprocess.Popen(my_cmd, shell=True)
os.waitpid(p.pid, 0)

OTOH, sistem çağrılarını tamamen önleyebilirsiniz:

import shutil

with open('myfile', 'w') as outfile:
    for infile in ('file1', 'file2', 'file3'):
        shutil.copyfileobj(open(infile), outfile)

1
Çalışıyor, ama o zaman size sormama izin verin: Eğer os.system işi zaten halletmişse, alt işlem kütüphanesinin anlamı nedir? Bunun yerine, bu göreve adanmış bir kütüphane olduğu için alt işlem kullanmam gerektiği hissine kapılıyorum, ancak bunu sadece kendim için yaptığım için bu sefer os.system'i kullanmakta sorun yaşamayacağım.
catatemypythoncode

Alt süreç kitaplığı, olduğundan çok daha esnektir os.systemve os.systemtam olarak modelleyebilir , ancak aynı zamanda çalışmak için daha karmaşıktır.
Marcelo Cantos

13
os.systemönce geldi subprocess. İlki, ikincisinin değiştirmeyi planladığı eski bir API'dir.
Noel Baba

5
@catatemypythoncode: os.system()veya kullanmamalısınız shell=True. Bir alt işlemin çıktısını yeniden yönlendirmek için stdout, Ryan Thompson'ın yanıtında gösterildiği gibi parametreyi kullanın . catSizin durumunuzda bir alt işleme ( ) ihtiyacınız olmasa da , dosyaları saf Python kullanarak birleştirebilirsiniz.
jfs

4
OTOH = Öte yandan
Cephlin

279

In Python 3.5+ çıkışını yönlendirmek için, sadece açık bir dosya tanıtıcı geçirmek stdoutiçin argüman subprocess.run:

# Use a list of args instead of a string
input_files = ['file1', 'file2', 'file3']
my_cmd = ['cat'] + input_files
with open('myfile', "w") as outfile:
    subprocess.run(my_cmd, stdout=outfile)

Diğerlerinin de belirttiği gibi cat, bu amaç için olduğu gibi harici bir komutun kullanılması tamamen gereksizdir.


9
Python kabuğu kullanılırken bu boruların genel sorunun yanıtı olmalıdır
Kaushik Ghose

47
Bu doğru cevaptır, doğru olarak işaretlenen değil.
Justin Blake

7
Yerine subprocess.run(my_cmd, stdout=outfile)geçen Python 3.5+ kullanımı içinsubprocess.call(...)
Austin Yates

1
Bir dosya alanlarına sahip değillerse (gerçek bir dosya değillerse), bu özel dosya nesneleriyle çalışmaz.
Eliezer Miron

1
Python <3.5 şu anda kullanımdan kaldırıldığından, cevabı @AustinYates yorumunuzla güncelledim.
Greg Dubicki

5

@PoltoS Bazı dosyaları birleştirmek ve ardından ortaya çıkan dosyayı işlemek istiyorum. Kedi kullanmanın en kolay alternatif olduğunu düşündüm. Bunu yapmanın daha iyi / pitonik bir yolu var mı?

Elbette:

with open('myfile', 'w') as outfile:
    for infilename in ['file1', 'file2', 'file3']:
        with open(infilename) as infile:
            outfile.write(infile.read())

1
size = 'ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 dump.mp4 > file'
proc = subprocess.Popen(shlex.split(size), shell=True)
time.sleep(1)
proc.terminate() #proc.kill() modify it by a suggestion
size = ""
with open('file', 'r') as infile:
    for line in infile.readlines():
        size += line.strip()

print(size)
os.remove('file')

Eğer kullandığınız zaman alt işlemi , killed.This olmalıdır süreç işlemi öldürmez bir example.If olduğu dosya boş olacak ve nothing.It yayınlanabilir okuyabilir , Windows emin olabilir olun can`t .I Unix üzerinde çalıştırın.


1
O (Unix üzerinde çalışmaz; kötü uygulamalarını izlediğini gösteren kötü bir kod örneği for line in .readlines():, s +=) ve proc.kill()) genel olarak bilgi kaybına yol açabilir (bu altişlem Unix üzerinde (incelikle sonlandırmak için izin vermez - unflushed içerik kaybolur ). Her neyse, arabelleğe alma ile ilgili not, yorum olarak daha uygundur.
jfs

Windows'ta çalıştırıyorum tamam (Çünkü öldürmek Windows'ta sonlandırmaya eşittir). Unix'te proc.terminate () kullanmanız gerekebilir. @ JF Sebastian Bilgisayarımda Unix Sistemim yok.
wyx

Windows üzerinde ise o zaman bırakın shlex.split(), damla shell=True, damla >file, damla open(), vb ve kullanımı stdout=PIPE, Timer(1, proc.terminate).start(); output = proc.communicate()[0]yerine. İşte tam bir örnek . Daha fazla çözüm: Python'da işlem çıktısını takılmadan okumayı durdur? Not: soruda alt süreci manuel olarak sonlandırmanız gerekmesine gerek yoktur - başka sorunları da ele alabilirsiniz, örneğin, bir sürecin stdout'u bir tty ise ancak konu dışı ise farklı davranabilir.
jfs

0

İlginç bir durum, bir dosyayı ona benzer bir dosya ekleyerek güncellemektir. O zaman işlem sırasında yeni bir dosya oluşturmak zorunda kalmazsınız. Büyük bir dosyanın eklenmesinin gerektiği durumlarda özellikle yararlıdır. İşte doğrudan python'dan teminal komut satırı kullanarak bir olasılık.

import subprocess32 as sub

with open("A.csv","a") as f:
    f.flush()
    sub.Popen(["cat","temp.csv"],stdout=f)
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.