2009-08-01 13 views
16

Ich verwende IO.popen in Ruby, um eine Reihe von Befehlszeilenbefehlen in einer Schleife auszuführen. Ich muss dann einen anderen Befehl außerhalb der Schleife ausführen. Der Befehl außerhalb der Schleife kann erst ausgeführt werden, wenn alle Befehle in der Schleife beendet wurden.Wie warten, bis der Prozess mit IO.popen beendet ist?

Wie kann ich das Programm darauf warten lassen? Im Moment läuft der letzte Befehl zu früh.

Ein Beispiel:

for foo in bar 
    IO.popen(cmd_foo) 
end 
IO.popen(another_cmd) 

Also alles cmd_foos müssen zurückkehren, bevor another_cmd ausgeführt wird.

Antwort

4

Ich denke, Sie müssten die Ergebnisse aus den IO.popen Aufrufe innerhalb des Zyklus auf die Variablen zuweisen, und rufen Sie read() auf ihnen, bis eof() wird wahr für alle.

Dann wissen Sie, dass alle Programme ihre Ausführung beendet haben und Sie another_cmd starten können.

+2

Nur als zusätzliche Anmerkung: die Blockform von IO Methoden ist in der Regel sicherer. In 1.9 erhalten Sie zusätzlich Robustheit, da Blockvariablen unterschiedliche Bereiche haben, die die Änderung von gleichnamigen Variablen außerhalb des Blocks verhindern (und Sie erhalten eine Warnung). –

6
for foo in bar 
    out = IO.popen(cmd_foo) 
    out.readlines 
end 
IO.popen(another_cmd) 

die Ausgabe in eine Variable Lese es dann ruft out.readlines tat. Ich denke, dass out.readlines muss warten, bis der Prozess endet, bevor es zurückkehrt.

Kredit an Andrew Y für mich in die richtige Richtung.

+0

Ich probierte genau dasselbe und endete mit Zombies (nicht mehr funktionstüchtig), also nicht ideal – nhed

+0

Es fehlt out.close –

3

Ich schlage vor, Sie Thread.join verwenden, um den letzten popen Aufruf zu synchronisieren:

t = Thread.new do 
    for foo in bar 
     IO.popen(cmd_foo) 
    end 
end 

t.join 

IO.popen(another_cmd) 
1

Sie benötigen die Ausgabe von popen? Wenn nicht, möchten Sie Kernel#system oder einen anderen Befehl verwenden?

18

die Blockform verwenden und den gesamten Inhalt lesen:

IO.popen "cmd" do |io| 
    # 1 array 
    io.readlines 

    # alternative, 1 big String 
    io.read 

    # or, if you have to do something with the output 
    io.each do |line| 
    puts line 
    end 

    # if you just want to ignore the output, I'd do 
    io.each {||} 
end 

Wenn Sie nicht über die Ausgabe lesen, kann es die Prozessblöcke sein, dass, weil das Rohr den anderen Prozess und Ihr Prozess ist voll und niemand verbindet liest daraus.

+0

Würde 'IO.open ('cmd'). Close' funktionieren, wenn stdout verwerfen? Docs sagen, es setzt '$?' (Also wartet), aber ich bin mir nicht sicher, es löscht auch alle stdout, ohne zu blockieren. –

+0

Was genau meinen Sie mit "stdout verwerfen"? Der angezeigte Code verwirft nichts. Wenn Sie nur etwas ausführen möchten und nichts Besonderes mit dem Ausgabesystem tun() ist passender, –

+0

von "verwerfen stdout" ich meinte "lesen Sie die Ausgabe", die diese Antwort möglicherweise erforderlich sein, um Blockierung zu verhindern. –

16

Anscheinend ist die canonical way dies zu tun ist:

Process.wait(popened_io.pid) 
+0

Diese Antwort ist die korrekteste. Keine Nebenwirkungen (wie bei io.read) und sehr offensichtlich, was es macht. – siannopollo

Verwandte Themen