2009-08-01 10 views
16

Używam IO.popen w Ruby, aby uruchomić serię komend wiersza poleceń w pętli. Następnie muszę uruchomić inne polecenie poza pętlą. Komenda poza pętlą nie może działać, dopóki wszystkie polecenia w pętli nie zostaną zakończone.Jak czekać na zakończenie procesu za pomocą IO.popen?

Jak sprawić, aby program czekał, aż to nastąpi? W tej chwili ostateczne polecenie działa zbyt szybko.

Przykład:

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

Więc cmd_foos muszą wrócić przed another_cmd jest prowadzony.

Odpowiedz

4

Myślę, że trzeba przypisać wyniki z wywołań IO.popen w ramach cyklu do zmiennych i nadal wywoływać na nich read() aż do momentu, gdy eof() stanie się prawdziwe.

Następnie wiesz, że wszystkie programy zakończyły wykonywanie i możesz rozpocząć another_cmd.

+2

Tylko jako dodatkowe Uwaga: za pomocą formularza blokowy metody IO jest zwykle bezpieczniejsze. Ponadto, w wersji 1.9 zwiększa się solidność, ponieważ zmienne blokowe mają różne zakresy, co uniemożliwia modyfikację tych samych nazwanych zmiennych poza blokiem (a otrzymasz ostrzeżenie). –

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

Zrobiłem to, odczytując wynik do zmiennej, a następnie wywołując out.readlines. Myślę, że out.readlines musi poczekać, aż proces się zakończy, zanim powróci.

Podziękowania dla Andrew Y za skierowanie mnie we właściwym kierunku.

+0

Próbowałem dokładnie to samo i skończyło się z zombie (nieistniejące), więc nie jest idealny – nhed

+0

Brakuje out.close –

3

Proponuję użyć Thread.join zsynchronizować ostatni popen połączenia:

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

t.join 

IO.popen(another_cmd) 
1

potrzebujesz wyjście popen? Jeśli nie, czy chcesz użyć Kernel#system lub innego polecenia?

18

Skorzystaj z formularza blok i przeczytać całą zawartość:

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 

Jeśli nie czytać wyjście może być tak, że blokuje proces, ponieważ rura łącząca inny proces i twój proces jest pełny i nikt czyta z niego.

+0

Czy 'IO.popen ('cmd'). Close' działa podczas odrzucania stdout? Dokumenty mówią, że ustawia '$?' (W ten sposób czeka), ale nie jestem pewien, czy odrzuca wszystkie standardowe wyjścia bez blokowania. –

+0

Co dokładnie masz na myśli przez "odrzucenie standardowego"? Wyświetlany kod niczego nie odrzuca. Jeśli chcesz po prostu wykonać coś i nie robić nic specjalnego w systemie wyjściowym() jest bardziej odpowiednie, –

+0

przez "odrzuć stdout" miałem na myśli "odczytać wynik", co może wymagać tej odpowiedzi, aby zapobiec blokowaniu. –

16

Widocznie canonical way to zrobić:

Process.wait(popened_io.pid) 
+0

Ta odpowiedź jest najbardziej poprawna. Brak efektów ubocznych (jak w przypadku io.read) i bardzo oczywiste, co robi. – siannopollo

Powiązane problemy