Wie kann ich Shell-Befehle aus einem Ruby-Programm heraus aufrufen? Wie bekomme ich dann die Ausgabe dieser Befehle zurück in Ruby?
Antworten
Zu viele Anzeigen?Diese Erklärung stützt sich auf eine kommentierte Ruby-Skript von einem Freund von mir. Wenn Sie das Skript verbessern möchten, können Sie es über den Link aktualisieren.
Zunächst ist zu beachten, dass Ruby bei Aufrufen einer Shell typischerweise /bin/sh
, no Bash. Einige Bash-Syntaxen werden nicht unterstützt von /bin/sh
auf allen Systemen.
Hier finden Sie Möglichkeiten zur Ausführung eines Shell-Skripts:
cmd = "echo 'hi'" # Sample string that can be used
-
Kernel#`
gemeinhin Backticks genannt -`cmd`
Das ist wie bei vielen anderen Sprachen, einschließlich Bash, PHP und Perl.
Gibt das Ergebnis (d.h. die Standardausgabe) des Shell-Befehls zurück.
Dokumente: http://ruby-doc.org/core/Kernel.html#method-i-60
value = `echo 'hi'` value = `#{cmd}`
-
Eingebaute Syntax,
%x( cmd )
Nach der
x
Zeichen ist ein Begrenzungszeichen, das ein beliebiges Zeichen sein kann. Wenn das Begrenzungszeichen eines der folgenden Zeichen ist(
,[
,{
, oder<
, besteht das Literal aus den Zeichen bis zum passenden schließenden Begrenzer, wobei verschachtelte Begrenzungszeichenpaare berücksichtigt werden. Bei allen anderen Begrenzungszeichen besteht das Literal aus den Zeichen bis zum nächsten Vorkommen des Begrenzungszeichens. Interpolation von Zeichenketten#{ ... }
ist erlaubt.Gibt das Ergebnis (d.h. die Standardausgabe) des Shell-Befehls zurück, genau wie die Backticks.
Dokumente: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-Percent+Saiten
value = %x( echo 'hi' ) value = %x[ #{cmd} ]
-
Kernel#system
Führt den angegebenen Befehl in einer Subshell aus.
Rückgabe
true
wenn der Befehl gefunden und erfolgreich ausgeführt wurde,false
sonst.Dokumente: http://ruby-doc.org/core/Kernel.html#method-i-system
wasGood = system( "echo 'hi'" ) wasGood = system( cmd )
-
Kernel#exec
Ersetzt den aktuellen Prozess durch die Ausführung des angegebenen externen Befehls.
Wird kein Wert zurückgegeben, wird der aktuelle Prozess ersetzt und nicht fortgesetzt.
Dokumente: http://ruby-doc.org/core/Kernel.html#method-i-exec
exec( "echo 'hi'" ) exec( cmd ) # Note: this will never be reached because of the line above
Hier noch ein paar zusätzliche Ratschläge: $?
, was dasselbe ist wie $CHILD_STATUS
greift auf den Status des zuletzt vom System ausgeführten Befehls zu, wenn Sie die Backticks verwenden, system()
o %x{}
. Sie können dann auf die exitstatus
y pid
Eigenschaften:
$?.exitstatus
Für weitere Informationen siehe:
Hier ist ein Flussdiagramm, das auf " Wann man welche Methode zum Starten eines Unterprozesses in Ruby verwendet ". Siehe auch: " Einer Anwendung vorgaukeln, dass ihr stdout ein Terminal und keine Pipe ist ".
Ich verwende dazu am liebsten die Methode %x
Literal, das es einfach (und lesbar!) macht, Anführungszeichen in einem Befehl zu verwenden, etwa so:
directorylist = %x[find . -name '*test.rb' | sort]
In diesem Fall wird die Dateiliste mit allen Testdateien im aktuellen Verzeichnis gefüllt, die Sie wie erwartet verarbeiten können:
directorylist.each do |filename|
filename.chomp!
# work with file
end
Hier ist der meiner Meinung nach beste Artikel über das Ausführen von Shell-Skripten in Ruby: " 6 Möglichkeiten, Shell-Befehle in Ruby auszuführen ".
Wenn Sie nur die Ausgabe erhalten möchten, verwenden Sie Backticks.
Ich brauchte fortgeschrittenere Dinge wie STDOUT und STDERR, also habe ich das Open4-Gem verwendet. Dort sind alle Methoden erklärt.
- See previous answers
- Weitere Antworten anzeigen
4 Stimmen
Diese Frage ist zwar nützlich, aber sie wird nicht gut gestellt. Ruby hat viele Möglichkeiten, Sub-Shells aufzurufen, die gut dokumentiert sind und leicht durch Lesen der Kernel y Öffnen3 Dokumentation und Suche hier auf SO.
3 Stimmen
Leider ist dieses Thema sehr komplex.
Open3
( docs ) ist die beste Wahl für die meisten Situationen, IMO, aber auf älteren Versionen von Ruby, wird es nicht respektieren eine modifiziertePATH
( bugs.ruby-lang.org/issues/8004 ), und je nachdem, wie Sie args übergeben (insbesondere, wenn Sie opts hash mit Nicht-Schlüsselwörtern verwenden), kann es zu einem Bruch kommen. Aber, wenn Sie diese Situationen treffen, dann tun Sie etwas ziemlich fortgeschritten und Sie können herausfinden, was zu tun ist, indem Sie die Implementierung vonOpen3
.6 Stimmen
Ich bin überrascht, dass niemand erwähnt hat
Shellwords.escape
( doc ). Sie möchten keine Benutzereingaben direkt in Shell-Befehle einfügen - geben Sie sie zuerst in einer Escape-Funktion ein! Siehe auch Befehlsinjektion .