2011-06-14 11 views
312

¿Cuál es la diferencia entre los siguientes métodos de Ruby?Ruby, diferencia entre exec, sistema y% x() o Backticks

exec, system y %x()o acentos abiertos

Sé que se utilizan para ejecutar comandos de terminal de programación a través de Ruby, pero me gustaría saber por qué hay tres maneras diferentes de hacer esto.

+5

Dado que alguien sólo desenterrado este viejo hilo, "Trabajar con procesos Unix" es un libro excelente para Rubyistas interesados ​​en el tema: http://workingwithunixprocesses.com/ –

+0

Hay una gran Rubí Artículo sobre este tema en QuickTips: [Ejecutar comandos de shell] (http://rubyquicktips.com/post/5862861056/execute-shell-commands). –

+1

Estos comandos, y muchos otros, se explican bastante bien en los documentos: [exec] (http://www.ruby-doc.org/core/Kernel.html#method-i-exec) [system] (http: //www.ruby-doc.org/core/Kernel.html#method-i-system) [backticks] (http://www.ruby-doc.org/core/Kernel.html#method-i-60) – zetetic

Respuesta

339

sistema

El método system llama a un programa del sistema. Debe proporcionar el comando como un argumento de cadena a este método. Por ejemplo:

>> system("date") 
Wed Sep 4 22:03:44 CEST 2013 
=> true 

El programa invocado usarán los actuales STDIN, STDOUT y STDERR objetos de su programa de Ruby. De hecho, el valor de retorno real es true, false o nil. En el ejemplo, la fecha se imprimió a través del objeto IO de STDIN. El método devolverá true si el proceso salió con un estado cero, false si el proceso salió con un estado distinto de cero y nil si la ejecución falló.

Otro efecto secundario es que la variable global $? se establece en un objeto Process::Status. Este objeto contendrá información sobre la llamada en sí, incluido el identificador de proceso (PID) del proceso invocado y el estado de salida.

>> system("date") 
Wed Sep 4 22:11:02 CEST 2013 
=> true 
>> $? 
=> #<Process::Status: pid 15470 exit 0> 

acentos abiertos

Backticks (``) llamar a un programa del sistema y volver a su salida. A diferencia del primer enfoque, el comando no se proporciona a través de una cadena, sino poniéndolo dentro de un par de retrocesos.

>> `date` 
=> Wed Sep 4 22:22:51 CEST 2013 

La variable global $? se establece a través de los acentos abiertos, también. Con los palos de retroceso también puede utilizar la interpolación de cadenas.

% x()

Usando %x es una alternativa al estilo acentos abiertos. Devolverá la salida, también. Al igual que sus parientes %w y %q (entre otros), cualquier delimitador será suficiente siempre que coincidan los delimitadores de estilo de corchete. Esto significa que %x(date), %x{date} y %x-date- son sinónimos. Al igual que los backticks %x pueden hacer uso de la interpolación de cadenas.

ejecutivo

Mediante el uso de Kernel#exec el proceso actual (la secuencia de comandos de Ruby) se sustituye por el procedimiento invocado a través exec. El método puede tomar una cadena como argumento. En este caso, la cadena estará sujeta a la expansión del caparazón. Cuando se usa más de un argumento, el primero se usa para ejecutar un programa y los siguientes se proporcionan como argumentos para invocar al programa.

Open3.popen3

A veces la información requerida se escribe en la entrada estándar o el error estándar y tiene que conseguir el control sobre esos también. Aquí Open3.popen3 viene muy bien:

require 'open3' 

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread| 
    pid = thread.pid 
    puts stdout.read.chomp 
end 
+1

Y para un control más detallado de cómo maneja la llamada 'STDIN',' STDOUT', 'STDERR', considere' Open3.popen3' en su lugar; p.ej. ver http://stackoverflow.com/a/10922097/258662 – cboettig

+1

@platzhirsch - Muy bien explicado. Gracias. – itsh

+0

Gracias, agregó. @cboettig –

91

Hacen cosas diferentes. exec reemplaza el proceso actual con el nuevo proceso y nunca devuelve. system invoca otro proceso y devuelve su valor de salida al proceso actual. El uso de barras inversas invoca otro proceso y devuelve la salida de ese proceso al proceso actual.

176

aquí es un diagrama de flujo basado en this answer. Ver también, using script to emulate a terminal.

enter image description here

+1

Esto no es tan simple. En mi caso "estaba bien (y necesito) bloquear hasta que el proceso se complete" para luego usar popen3 para verificar las salidas STDOUT/STDERR. – Nakilon

+0

Siempre puede causar que una llamada no bloqueada bloquee (efectivamente) envolviéndola en un ciclo while. No puede realizar una llamada de bloqueo en una llamada sin bloqueo tan fácilmente. – Ian

Cuestiones relacionadas