Ruby, Unterschied zwischen exec, system und% x () oder Backticks

370

Was ist der Unterschied zwischen den folgenden Ruby-Methoden?

exec, systemUnd %x()oder Backticks

Ich weiß, dass sie verwendet werden, um Terminalbefehle programmgesteuert über Ruby auszuführen, aber ich möchte wissen, warum es drei verschiedene Möglichkeiten gibt, dies zu tun.

Herr Schwarz
quelle
1
Diese Befehle, und viele andere, sind recht gut in der Dokumentation erklärt: exec System Backticks
zetetic
1
Zu diesem Thema gibt es einen großartigen Ruby Quicktips-Artikel: Ausführen von Shell-Befehlen .
Simon Perepelitsa
6
Da gerade jemand diesen alten Thread ausgegraben hat, ist "Arbeiten mit Unix-Prozessen" ein ausgezeichnetes Buch für Rubyisten, die sich für das Thema interessieren: workingwithunixprocesses.com
Michael Kohl
1
Ich bin überrascht, dass keine der Antworten erwähnt wird sh.
Dennis
@ Tennis Als ich diese Frage stellte, wurde Ruby 1.9.3 * nicht veröffentlicht.
Mr. Black

Antworten:

411

System

Die systemMethode ruft ein Systemprogramm auf. Sie müssen den Befehl als Zeichenfolgenargument für diese Methode angeben. Zum Beispiel:

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

Das aufgerufene Programm wird die aktuelle verwenden STDIN, STDOUTund STDERRObjekte Ihrer Ruby - Programm. In der Tat ist der tatsächliche Rückgabewert entweder true, falseoder nil. Im Beispiel wurde das Datum über das E / A-Objekt von gedruckt STDIN. Die Methode wird zurückgegeben, truewenn der Prozess mit einem Nullstatus beendet wurde, falsewenn der Prozess mit einem Status ungleich Null beendet wurde und nilwenn die Ausführung fehlgeschlagen ist.

Ein weiterer Nebeneffekt ist, dass die globale Variable $?auf ein Process::StatusObjekt festgelegt ist. Dieses Objekt enthält Informationen zum Aufruf selbst, einschließlich der Prozesskennung (PID) des aufgerufenen Prozesses und des Beendigungsstatus.

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

Backticks

Backticks (``) rufen ein Systemprogramm auf und geben dessen Ausgabe zurück. Im Gegensatz zum ersten Ansatz wird der Befehl nicht über eine Zeichenfolge bereitgestellt, sondern durch Einfügen in ein Backtick-Paar.

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

Die globale Variable $?wird auch über die Backticks festgelegt. Mit Backticks können Sie auch die String-Interpolation verwenden.

% x ()

Die Verwendung %xist eine Alternative zum Backticks-Stil. Es wird auch die Ausgabe zurückgeben. Wie seine Verwandten %wund %q(unter anderem) wird jedes Trennzeichen ausreichen, solange Trennzeichen im Klammerstil übereinstimmen. Dieses Mittel %x(date), %x{date}und %x-date-sind alle Synonyme. Wie Backticks%x können die String-Interpolation nutzen.

exec

Durch die Nutzung Kernel#exec des aktuellen Prozesses (Ihr Ruby-Skript) wird der durch aufgerufene Prozess ersetzt exec. Die Methode kann eine Zeichenfolge als Argument verwenden. In diesem Fall wird die Zeichenfolge einer Shell-Erweiterung unterzogen. Wenn Sie mehr als ein Argument verwenden, wird das erste zum Ausführen eines Programms verwendet, und die folgenden Argumente werden als Argumente für das aufzurufende Programm bereitgestellt.

Open3.popen3

Manchmal werden die erforderlichen Informationen in Standardeingaben oder Standardfehler geschrieben, und Sie müssen auch die Kontrolle darüber erlangen. Hier ist Open3.popen3praktisch:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end
Konrad Reiche
quelle
3
Und für eine feinkörnige Steuerung, wie die Call - Griffe STDIN, STDOUT, STDERR, betrachten Open3.popen3statt; zB siehe stackoverflow.com/a/10922097/258662
cboettig
1
Vielen Dank für die Erwähnung, dass Backticks die String-Interpolation unterstützen, wodurch mein Problem gelöst wurde.
adg
244

Hier ist ein Flussdiagramm, das auf dieser Antwort basiert . Siehe auch Verwenden scriptzum Emulieren eines Terminals .

Geben Sie hier die Bildbeschreibung ein

Ian
quelle
3
Das ist nicht so einfach. In meinem Fall war es "OK (und musste blockiert werden), bis der Prozess abgeschlossen ist", um dann mit popen3 die STDOUT / STDERR-Ausgänge zu überprüfen.
Nakilon
Sie können einen nicht blockierenden Aufruf jederzeit (effektiv) blockieren lassen, indem Sie ihn in eine while-Schleife einschließen. Sie können einen blockierenden Anruf nicht so einfach in einen nicht blockierenden Anruf umwandeln.
Ian
106

Sie machen verschiedene Dinge. execErsetzt den aktuellen Prozess durch den neuen Prozess und kehrt nie zurück . systemruft einen anderen Prozess auf und gibt seinen Exit-Wert an den aktuellen Prozess zurück. Die Verwendung von Backticks ruft einen anderen Prozess auf und gibt die Ausgabe dieses Prozesses an den aktuellen Prozess zurück.

William Pursell
quelle