2009-08-01 23 views
16

Estoy usando IO.popen en Ruby para ejecutar una serie de comandos de línea de comandos en un bucle. Entonces necesito ejecutar otro comando fuera del ciclo. El comando fuera del bucle no puede ejecutarse hasta que todos los comandos en el bucle hayan terminado.¿Cómo esperar a que el proceso termine de usar IO.popen?

¿Cómo hago para que el programa espere a que esto suceda? Por el momento, el comando final se está ejecutando demasiado pronto.

Un ejemplo:

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

Así que todo cmd_foos necesidad de volver antes de ejecutar another_cmd.

Respuesta

4

creo que lo que se necesita para asignar los resultados de las IO.popen llamadas dentro del ciclo de las variables, y seguir llamando read() en ellos hasta eof() se convierte en verdad en absoluto.

Entonces sabes que todos los programas han terminado su ejecución y puedes comenzar another_cmd.

+2

Así como una nota adicional: el uso de la forma de bloque de los métodos de Io es generalmente más seguro. Además, en 1.9 usted obtiene robustez adicional porque las variables de bloque tienen un alcance diferente que impide la modificación de las mismas variables nombradas fuera del bloque (y obtendrá una advertencia). –

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

Lectura de la salida a una variable que luego llama a out.readlines lo hizo. Creo que out.readlines debe esperar a que el proceso finalice antes de que vuelva.

Gracias a Andrew Y por señalarme en la dirección correcta.

+0

Probé exactamente lo mismo y terminé con zombies (desaparecidos), por lo que no es ideal – nhed

+0

Se está perdiendo out.close –

3

le sugiero que utilice Thread.join para sincronizar la última popen llamada:

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

t.join 

IO.popen(another_cmd) 
1

¿Necesita la salida de popen? Si no, ¿quiere usar Kernel#system o algún otro comando?

18

Use la forma de bloques y leer todo el contenido:

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 

Si usted no lee la salida, puede ser que los bloques de proceso debido a que el tubo que conecta el otro proceso y el proceso está lleno y nadie lee de eso.

+0

¿Funcionaría 'IO.popen ('cmd'). Close' al desechar stdout? Los documentos dicen que establece '$?' (Por lo tanto, espera), pero no estoy seguro de que también descarta todos los stdout sin bloqueo. –

+0

¿Qué quiere decir exactamente con "descartar stdout"? El código que muestra no descarta nada. Si desea ejecutar algo y no hacer nada especial con el sistema de salida() es más apropiado, –

+0

por "descartar stdout" Quise decir "leer el resultado", que esta respuesta puede ser necesaria para evitar el bloqueo. –

16

Al parecer, el canonical way de hacer esto es:

Process.wait(popened_io.pid) 
+0

Esta respuesta es la más correcta. Sin efectos secundarios (como con io.read), y muy obvio lo que está haciendo. – siannopollo

Cuestiones relacionadas