2010-07-06 19 views
16

dosyasına yazıyorum. Herbiri stdout üreten iki program (derlenmiş C kodundan) yürütmek için altprocess.Popen kullanan bir python komut dosyası yazıyorum. Komut bu çıktıyı alır ve bir dosyaya kaydeder. Çıktı bazen altprogram.PIPE, komut dosyasının askıda kalmasına neden olacak kadar büyük olduğundan, stdout'u doğrudan günlük dosyasına gönderirim. Komut dosyamın başlangıcına ve sonuna bir şey yazmasını istiyorum ve iki alt işlem arasında .Popen çağrıları. Ancak, günlük dosyama baktığımda, komut dosyasından günlük dosyasına yazdığım her şey, dosyanın üst kısmında, sonra da tüm yürütülebilir stdout'lar tarafından izlenir. Eklenmiş metnimi dosyaya nasıl ekleyebilirim?Altprogramdan stdout'u kaydetme.Popen dosyasını dosyaya yazıp, daha fazla dosyaya

def run(cmd, logfile): 
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) 
    return p 

def runTest(path, flags, name): 
    log = open(name, "w") 
    print >> log, "Calling executable A" 
    a_ret = run(path + "executable_a_name" + flags, log) 
    print >> log, "Calling executable B" 
    b_ret = run(path + "executable_b_name" + flags, log) 
    print >> log, "More stuff" 
    log.close() 

günlük dosyası vardır: yürütülebilir B çağrılması yürütülebilir bir çağrılması Daha şeyler [... Her iki yürütülebilir gelen stdout'u ...]

ben A'nın stdout'u temizlemek bir yolu var mı Örneğin, Popen'i aradıktan sonra günlük? Alakalı olabilecek bir şey daha: Çalıştırılabilir A başlangıçlar B'ye bürünüyor ve B, bir şeyler basıp bitirdikten sonra, A daha fazla şey basıyor ve bitiriyor.

RHE Linux üzerinde Python 2.4 kullanıyorum.

+0

stdout = subprocess.PIPE kullanıldığında ve dış döngü her şeyi günlük dosyasına yazdığında, kendi metnimi yürütücünün çıktısıyla arayabilirdim. Metin eklemediğimde, günlüğün içeriği şu sırayla olur: 1) Bir çıkış 2) B çıkışı 3) geri kalan A çıkışı. Bu adımlardan önce veya sonra metin ekleyebilirim. Şimdi sadece günlüğün başlangıcında veya sonunda metin ekleyebilirim. Popen komut dosyasını çektikten sonra bekle() ekledikten sonra B A bitene kadar başlamaz, çünkü A olmazsa olmaz, çünkü A, el sıkışmasını B'den bekler. Bu yaklaşımla günlük metninde kendi aramamı ayırmak mümkün mü? – jasper77

cevap

15

Bitirildiğinden emin olmak için her Popen nesnesinde .wait() öğesini çağırabilir ve ardından log.flush() öğesini çağırabilirsiniz. Böyle Belki bir şey:

def run(cmd, logfile): 
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) 
    ret_code = p.wait() 
    logfile.flush() 
    return ret_code 

Eğer .wait hareket olabilir sizin dış fonksiyonundaki POPEN bir nesneyle etkileşim gerekiyorsa() yerine orada diyoruz.

+1

run() işlevine wait() koyarsam, B yürütülebilir, A bitene kadar çalışmaya başlamaz ve A B bitene kadar bitmediğinden, komut dizisi asılırdı. Ancak, runTest() işlevini çalıştırırsam, A ve B komutlarını çalıştırırsam ve A kaydını beklediğimde ve çalışma günlüğünü temizlediğimde, runTest öğesinin sonunda yazdığım bir satırın günlük dosyasının sonunda gösterildiğini buldum. Hala B'den hemen önce dosyaya yazı yazmanın bir yolunu bulamadım. Bir yolu olduğunu bilmiyorum. – jasper77

+2

'logfile.flush()' ın alt süreçler üzerinde bir etkisi yoktur. – jfs

1

Devam etmeden önce işlem bitene kadar beklemeniz gerekir. Ayrıca kodu, daha temiz olan bir içerik yöneticisi kullanacak şekilde dönüştürdüm.

def run(cmd, logfile): 
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) 
    p.wait() 
    return p 

def runTest(path, flags, name): 
    with open(name, "w") as log: 
     print >> log, "Calling executable A" 
     a_ret = run(path + "executable_a_name" + flags, log) 
     print >> log, "Calling executable B" 
     b_ret = run(path + "executable_b_name" + flags, log) 
     print >> log, "More stuff" 
+0

İçerik yöneticileri, halen RHEL5 sistemlerini çalıştıran herkes için uygun olmayan bir python2.6 özelliğidir. RHEL6 çıkana kadar, onları kullanmamak en iyisidir. – Jerub

+0

Python 2.5'teki içerik yöneticilerini, herhangi bir diğer içe aktarmadan önce '__future__ import with_statement' kullanarak' kullanabilirsiniz. – detly

+0

Ancak, RHEL5'in Python 2.4'te sıkışmış gibi görünüyor. –

2

Sadece basit kalmasını sağlıyorum. Sözde kod temel mantığı: Sadece B çıkar sonra onun şeyi ve A çıkar yapmak B için A programı bekler Anladığım kadarıyla

write your start messages to logA 
execute A with output to logA 
write your in-between messages to logB 
execute B with output to logB 
write your final messages to logB 
when A & B finish, write content of logB to the end of logA 
delete logB 
+0

Tek bir günlük dosyası yerine A ve B için iki ayrı günlük dosyası kullanmak için kutu dışında düşünme önerisi için teşekkür ederiz. Bunu düşünmek zorundayım. – jasper77

1

.

B o zaman ters sırada süreçleri başlatabilir çalışan A olmadan başlatabilirsiniz:

from os.path import join as pjoin 
from subprocess import Popen 

def run_async(cmd, logfile): 
    print >>log, "calling", cmd 
    p = Popen(cmd, stdout=logfile) 
    print >>log, "started", cmd 
    return p 

def runTest(path, flags, name): 
    log = open(name, "w", 1) # line-buffered 
    print >>log, 'calling both processes' 
    pb = run_async([pjoin(path, "executable_b_name")] + flags.split(), log) 
    pa = run_async([pjoin(path, "executable_a_name")] + flags.split(), log) 
    print >>log, 'started both processes' 
    pb.wait() 
    print >>log, 'process B ended' 
    pa.wait() 
    print >>log, 'process A ended' 
    log.close() 

Not: Ana süreçlerde log.flush() çağıran çocuk süreçlerinde dosya tampon üzerinde hiçbir etkisi yoktur.

Alt süreçler, blok işlemleri için stdout'u kullanırsa, daha sonra pexpect, pty, or stdbuf'u kullanarak temizlemeye zorlamayı deneyebilirsiniz (bu, işlemlerin etkileşimli olarak çalıştırılırsa satır ara belleğini kullandığını veya G/Ç için C stdio kitaplığını kullandığını varsayar).