Ruby, Differenza tra exec, system e% x () o Backtick


370

Qual è la differenza tra i seguenti metodi di Ruby?

exec, systemE %x()o backtick

So che vengono utilizzati per eseguire i comandi di terminale a livello di codice tramite Ruby, ma mi piacerebbe sapere perché ci sono tre modi diversi per farlo.


1
Questi comandi, e molti altri, sono spiegati molto bene nella documentazione: exec sistema backticks
Zetetic

1
C'è un ottimo articolo su Ruby Quicktips sull'argomento: Esegui comandi shell .
Simon Perepelitsa,

6
Dato che qualcuno ha appena scoperto questo vecchio thread, "Lavorare con i processi Unix" è un libro eccellente per i rubyisti interessati all'argomento: workingwithunixprocesses.com
Michael Kohl,

1
Sono sorpreso che nessuna delle risposte menzioni sh.
Dennis,

@Dennis Quando stavo sollevando questa domanda ruby ​​1.9.3 * non rilasciato.
Mr. Black

Risposte:


411

sistema

Il systemmetodo chiama un programma di sistema. Devi fornire il comando come argomento stringa a questo metodo. Per esempio:

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

Il programma richiamato userà la corrente STDIN, STDOUTe STDERRgli oggetti del vostro programma Ruby. Infatti, il valore restituito effettivo è o true, falseo nil. Nell'esempio la data è stata stampata attraverso l'oggetto IO di STDIN. Il metodo restituirà truese il processo è terminato con uno stato zero, falsese il processo è terminato con uno stato diverso da zero e nilse l'esecuzione non è riuscita.

Un altro effetto collaterale è che la variabile globale $?è impostata su un Process::Statusoggetto. Questo oggetto conterrà informazioni sulla chiamata stessa, incluso l'identificatore del processo (PID) del processo richiamato e lo stato di uscita.

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

apici inversi

Backticks (``) chiama un programma di sistema e ne restituisce l'output. A differenza del primo approccio, il comando non viene fornito tramite una stringa, ma inserendolo in una coppia di backtick.

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

Anche la variabile globale $?viene impostata attraverso i backtick. Con i backtick puoi anche usare l'interpolazione di stringhe.

%X()

L'utilizzo %xè un'alternativa allo stile di backtick. Restituirà anche l'output. Come i suoi parenti %we %q(tra gli altri), qualsiasi delimitatore sarà sufficiente finché i delimitatori in stile parentesi corrispondono. Questo mezzo %x(date), %x{date}e %x-date-sono tutti sinonimi. Come i backtick %xpossono usare l'interpolazione di stringhe.

exec

Utilizzando Kernel#execil processo corrente (il tuo script Ruby) viene sostituito con il processo richiamato exec. Il metodo può prendere una stringa come argomento. In questo caso la stringa sarà soggetta all'espansione della shell. Quando si utilizza più di un argomento, il primo viene utilizzato per eseguire un programma e vengono forniti come argomenti al programma da invocare.

Open3.popen3

A volte le informazioni richieste vengono scritte nell'input standard o nell'errore standard ed è necessario avere il controllo anche su quelle. Ecco Open3.popen3utile:

require 'open3'

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

3
E per di più a grana fine il controllo di come le maniglie delle chiamate STDIN, STDOUT, STDERR, considerano Open3.popen3invece; ad esempio, vedere stackoverflow.com/a/10922097/258662
cboettig

1
Grazie per aver menzionato che i backtick supportano l'interpolazione di stringhe che ha risolto il mio problema.
adg

244

Ecco un diagramma di flusso basato su questa risposta . Vedi anche, usando scriptper emulare un terminale .

inserisci qui la descrizione dell'immagine


3
Questo non è così semplice Nel mio caso "era OK (e necessitava) bloccare fino al completamento del processo" per poi usare popen3 per controllare le uscite STDOUT / STDERR.
Nakilon,

Puoi sempre far bloccare (efficacemente) una chiamata non bloccante avvolgendola in un ciclo while. Non è possibile effettuare una chiamata bloccante in una chiamata non bloccante così facilmente.
Ian,

106

Fanno cose diverse. execsostituisce il processo corrente con il nuovo processo e non ritorna mai . systeminvoca un altro processo e restituisce il valore di uscita al processo corrente. L'uso dei backtick invoca un altro processo e restituisce l'output di quel processo al processo corrente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.