Ruby, diferencia entre exec, sistema y% x () o Backticks

370

¿Cuál es la diferencia entre los siguientes métodos de Ruby?

exec, systemY %x()o acentos abiertos

Sé que se usan para ejecutar comandos de terminal mediante programación a través de Ruby, pero me gustaría saber por qué hay tres formas diferentes de hacerlo.

El Sr. Black
fuente
1
Estos comandos, y muchos otros, se explican bastante bien en los documentos: exec sistema acentos abiertos
Zetetic
1
Hay un excelente artículo de Ruby Quicktips sobre ese tema: Ejecutar comandos de shell .
Simon Perepelitsa
66
Dado que alguien acaba de desenterrar este viejo hilo, "Trabajar con procesos Unix" es un excelente libro para los rubíes interesados ​​en el tema: workingwithunixprocesses.com
Michael Kohl
1
Me sorprende que ninguna de las respuestas mencione sh.
Dennis
@Dennis Cuando estaba planteando esta pregunta, Ruby 1.9.3 * no se lanzó.
Sr. Black

Respuestas:

411

sistema

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

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

El programa invocado utilizará la corriente STDIN, STDOUTy STDERRlos objetos de su programa de Ruby. De hecho, el valor de retorno real es true, falseo nil. En el ejemplo, la fecha se imprimió a través del objeto IO de STDIN. El método regresará truesi el proceso salió con un estado cero, falsesi el proceso salió con un estado distinto de cero y nilsi la ejecución falló.

Otro efecto secundario es que la variable global $?se establece en un Process::Statusobjeto. 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>

Backticks

Las teclas de retroceso (``) llaman a un programa del sistema y devuelven 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 backticks.

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

La variable global también $?se establece a través de los backticks. Con los backticks también puede hacer uso de la interpolación de cadenas.

%X()

Usar %xes una alternativa al estilo de backticks. También devolverá la salida. Al igual que sus parientes %wy %q(entre otros), cualquier delimitador será suficiente siempre que coincidan los delimitadores de estilo de soporte. Esto significa %x(date), %x{date}y %x-date-son todos sinónimos. Al igual que los backticks %xpueden hacer uso de la interpolación de cadenas.

ejecutivo

Al usar Kernel#execel proceso actual (su script Ruby) se reemplaza con el proceso invocado exec. El método puede tomar una cadena como argumento. En este caso, la cadena estará sujeta a la expansión del shell. Cuando se usa más de un argumento, el primero se usa para ejecutar un programa y los siguientes se proporcionan como argumentos para el programa que se va a invocar.

Open3.popen3

A veces, la información requerida se escribe en la entrada estándar o en el error estándar y usted también necesita controlarlos. Aquí Open3.popen3viene útil:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end
Konrad Reiche
fuente
3
Y para un control más detallado de cómo maneja llamadas STDIN, STDOUT, STDERR, consideran Open3.popen3su lugar; por ejemplo, consulte stackoverflow.com/a/10922097/258662
cboettig el
1
Gracias por mencionar que los backticks admiten la interpolación de cadenas que resolvió mi problema.
adg
244

Aquí hay un diagrama de flujo basado en esta respuesta . Ver también, usar scriptpara emular un terminal .

ingrese la descripción de la imagen aquí

Ian
fuente
3
Esto no es tan simple. En mi caso, "estaba bien (y necesito) bloquear hasta que se complete el proceso" para luego usar popen3 para verificar las salidas STDOUT / STDERR.
Nakilon
Siempre puede hacer que una llamada sin bloqueo se bloquee (efectivamente) envolviéndola en un ciclo while. No puede convertir una llamada de bloqueo en una llamada de no bloqueo tan fácilmente.
Ian
106

Ellos hacen cosas diferentes. execreemplaza el proceso actual con el nuevo proceso y nunca regresa . systeminvoca otro proceso y devuelve su valor de salida al proceso actual. El uso de backticks invoca otro proceso y devuelve la salida de ese proceso al proceso actual.

William Pursell
fuente