2011-03-04 9 views
5

Cuando se utiliza una llamada al sistema en un script Ruby, se puede obtener la salida de ese comando como este:¿Puedo obtener un resultado continuo de las llamadas al sistema en Ruby?

output = `ls` 
puts output 

Eso es lo que estaba a punto this question.

Pero, ¿hay alguna manera de mostrar la salida continua de de una llamada al sistema? Por ejemplo, si ejecuta este comando copia segura, para obtener un archivo de un servidor a través de SSH:

scp [email protected]:remoteFile /some/local/folder/ 

... que muestra la salida continua con el progreso de la descarga. Pero esto:

output = `scp [email protected]:remoteFile /some/local/folder/` 
puts output 

... no captura esa salida.

¿Cómo puedo mostrar el progreso continuo de la descarga desde mi script de Ruby?

+1

que tenían dos problemas ortogonales aquí, porque scp sólo produce la salida a los terminales de forma predeterminada, es necesario SCP * * -v – tokland

+0

@tokland - que pone a mensajes de depuración de salida, pero no el progreso de la transferencia que vería si solo ejecuté scp solo. Creo que no deben ir a la salida estándar, y no veo una opción para que scp los envíe allí. –

+0

Aparentemente scp envía esa información de progreso a "terminal interactivo"? No estoy seguro de cómo capturar eso ... –

Respuesta

9

Probar:

IO.popen("scp -v [email protected]:remoteFile /local/folder/").each do |fd| 
    puts(fd.readline) 
end 
+0

Esto funciona para obtener mensajes de salida estándar, pero parece que no es donde scp está enviando su progreso de transferencia. Así que supongo que mi problema es con scp ahora. –

+0

Esto responde a la pregunta tal como la hice; el hecho de que scp no produzca resultados normales resultó ser un detalle inesperado. –

+0

Consulte mi respuesta a continuación para saber cómo pude obtener esa salida de la biblioteca estándar de Ruby. –

0

¿Has probado con IO.popen? debería poder leer la salida mientras el proceso aún se está ejecutando y analizarlo en consecuencia.

3

creo que tendría mejor suerte usando la biblioteca estándar de rubí para manejar SCP (en contraposición a bifurcar un proceso de shell). La biblioteca Net :: SCP (y todas las bibliotecas Net :: *) tienen todas las funciones y se usan con Capistrano para manejar comandos remotos.

Pagar http://net-ssh.rubyforge.org/ para ver un resumen de lo que está disponible.

+0

¡Esto parece realmente prometedor! La documentación de net-scp está aquí: http://net-ssh.github.com/scp/v1/api/index.html Además, este tutorial muestra cómo generar progreso durante la transferencia: http: //ruby.about. com/od/ssh/ss/netscp_4.htm –

+0

Esto es lo que terminé haciendo. Pude mostrar un contador continuo del progreso de la descarga al pasar un bloque al objeto scp. Ver mi respuesta para el guion completo. –

0

Redirigir stderr a stdout puede funcionar para usted:

output = `scp [email protected]:remoteFile /some/local/folder/ 2>&1` 
puts output 

Eso debería captar tanto stderr y stdout. Puede capturar stderr solamente por tirar la salida estándar:

output = `scp [email protected]:remoteFile /some/local/folder/ 2>&1 >/dev/null` 
puts output 

continuación, se puede utilizar IO.popen.

2

Tokland respondió la pregunta tal como yo lo hice, pero el enfoque de Adam fue el que terminé usando. Aquí estaba mi script completo, que hace muestra un conteo de bytes descargados, y también un porcentaje completo.

require 'rubygems' 
require 'net/scp' 
puts "Fetching file" 

# Establish the SSH session 
ssh = Net::SSH.start("IP Address", "username on server", :password => "user's password on server", :port => 12345) 

# Use that session to generate an SCP object 
scp = ssh.scp 

# Download the file and run the code block each time a new chuck of data is received 
scp.download!("path/to/file/on/server/fileName", "/Users/me/Desktop/") do |ch, name, received, total| 

    # Calculate percentage complete and format as a two-digit percentage 
    percentage = format('%.2f', received.to_f/total.to_f * 100) + '%' 

    # Print on top of (replace) the same line in the terminal 
    # - Pad with spaces to make sure nothing remains from the previous output 
    # - Add a carriage return without a line feed so the line doesn't move down 
    print "Saving to #{name}: Received #{received} of #{total} bytes" + " (#{percentage})    \r" 

    # Print the output immediately - don't wait until the buffer fills up 
    STDOUT.flush 
end 

puts "Fetch complete!" 
+0

Sí, este es el mejor enfoque, cuando se usan buenos lenguajes solo es lógico confiar en sus bibliotecas. – tokland

Cuestiones relacionadas