2016-03-31 33 views
0

Bir parçası olarak perl betiği çalıştıran bir python betiğim var. stdout ve stderr'u subprocess modülünü kullanarak yürütüyorum ve yakalarım; Sözdizim kodu:Python: Bir dosyaya ilerleme çubuğu yazma

import subprocess as sp 
import sys 
perl_script='/usr/.../foo.pl' 
p = sp.Popen(perl_script,stdout=sp.PIPE,stderr=sp.PIPE) 
fname='test.log' 
shell_out=True 
text = '' 
with open(fname, 'w') as log: 
    while True: 
     data = p.stdout.read(1) 
     if data == '' and p.poll() != None: 
      break 
     if data != '': 
      if shell_out is True: 
       sys.stdout.write(data) 
       sys.stdout.flush() 
      log.write(data) 
    p.stdout.close() 

Döngünün her yinelemesi için, veri tek bir dize karakteri gibi görünüyor.

Yapmakta olduğum sorun, bu perl betiğinin üzerine yazdığı bir ilerleme çubuğu göstermesidir;

[#####.....] 50% 

ve her 5% bir güncelleştirme. Bu şekilde, yazdığım günlük dosyası şu satırlar boyunca bir şeye sahip olur:

.

Günlük dosyasımda bir önceki satırın üzerine yazmam için bir yöntem veya yöntem var mı, yoksa tüm metni yakalamak, değiştirmeyi denemek ve bir günlük dosyasına yazmak için tek seçeneğim var mı?

Düzenleme: Verdiğim örneğin basit doğasının tüm hikayeyi anlatamayacağını düşünüyorum. Bu perl betiği çoklu ilerleme çubuklarına (her görev için bir tane) sahiptir ve günlüğe kaydetmek istediğim ek bilgileri verir. Daha detaylı örnektir:

NOTICE: one or more of things did stuff and you probably want to take note of it 
writing the foo file . . . 
    writing things . . .        [####################] 100% 
    writing stuff . . .        [####################] 100% 
    writing items . . .        [####################] 100% 
done 
creating other files... 
done 

Yukarıdaki çıktı bu perl script stdout özelliklerini eşleşen bir örnek olduğunu ve gerçek çıkış (I gönderemezsiniz olan) yaklaşık 100 ya da unutmayın bu yüzden çizgiler.

Son olarak, biçimlendirme yardım :) için teşekkürler

Düzenleme # 2: Ben stdout yakalandığında olarak günlük dosyası yazmaya çalışıyorum vazgeçmiş ettik ve bunun yerine bir değişkende stdout depolamak ve yazacak komut dosyası bittikten sonra günlük dosyası. Geriye kalan tek sorun, dizenin düzgün bir şekilde nasıl biçimlendirileceğidir, böylece günlük dosyası doğru şekilde yazılır. Her durum çubuğunun her yüzdesi için bir çizgide bu kod sonuçları Şu anda

import subprocess as sp 
import sys 
tg_post='/usr/.../foo.pl' 
p = sp.Popen(tg_post,stdout=sp.PIPE) 
text = '' 
fname='test.log' 
shell_out=True 
while True: 
    data = p.stdout.read(1) 
    if data == '' and p.poll() != None: 
     break 
    if data != '': 
     if shell_out is True: 
      sys.stdout.write(data) 
      sys.stdout.flush() 
     text += data   
p.stdout.close() 
text = text.split('\r') 
with open(fname, 'w') as log: 
    log.write(text) 

: güncellenmiş sözde kodudur. Sanırım her bir dizinin üzerine metin yazabilirim (bölme sonrası) ve # ve 100% değil bir dizini kaldırabilirim, ama daha sağlam bir şey olduğunu umuyorum. print text (bölünme sonrası) ise, ekranda istediğimi alırım. Bir dosyaya yazmak için print kullanmanın mümkün olduğunu biliyorum, ancak bundan kaçınmak istiyorum (bu yöntemin artık kullanılmadığına inanıyorum).

+0

Neden günlük dosyanızdaki satırların üzerine yazmak istersiniz? –

+0

@ nathan.meadows - Günlük dosyamdaki satırları yazmazsam, okunması kolay bir ~ 100 satır dosyası yerine, bazı satırların 1600 karakter uzunluğunda olduğu ~ 50 satırlık bir dosyadır. – Shaun

cevap

0

Verileri while döngüsünün dışında tanımlayabilir ve son durumu en sonunda dosyaya yazabilirsiniz. Böylelikle, dosya tarafından tutulan son durum güncellemesi, dosyanın son durumunu sürekli olarak yazmasını engeller.

import subprocess as sp 
import sys 
perl_script='/usr/.../foo.pl' 
p = sp.Popen(perl_script,stdout=sp.PIPE,stderr=sp.PIPE) 
fname='test.log' 
shell_out=True 
text = '' 
data = '' 

while True: 
    data = p.stdout.read(1) 
    if data == '' and p.poll() != None: 
     break 
    if data != '': 
     if shell_out is True: 
      sys.stdout.write(data) 
      sys.stdout.flush() 
    p.stdout.close() 
with open(fname, 'w') as log: 
    log.write(data) 
+0

Buradaki sorun, verilerin her zaman tek bir karakter olmasıdır, bu nedenle bu perl komut dosyasının özellikleri için, bu yalnızca '\ n' olan bir günlük dosyasına neden olur.Veriyi her bir yinelemeye ekleyebilirim ve sonra döngüden sonra 'verileri' değiştirebilirim, ancak stdout'u aldığımda günlük dosyasını yazmayı umuyordum. – Shaun

+0

Gittiğiniz gibi yapmak istediğin sebeplerin neler? Ve [.strip()] (https://docs.python.org/2/library/stdtypes.html#str.strip) bu durumda kullanılabilir olabilir – heinst

+0

Daha fazla düşünürsem, daha az önemli düşünüyorum 'stdout' yakaladığında günlük dosyasını yazmak üzeredir. Bu, tek sorun, üzerine yazılacak tüm satırları kaldırmak için metnin biçimlendirilmesidir. Orijinal gönderiyi buna göre güncelleyeceğim. – Shaun