Wie rufe ich Shell-Befehle innerhalb eines Ruby-Programms auf? Wie bekomme ich dann von diesen Befehlen wieder zurück in Ruby?
Wie rufe ich Shell-Befehle innerhalb eines Ruby-Programms auf? Wie bekomme ich dann von diesen Befehlen wieder zurück in Ruby?
Diese Erklärung basiert auf einem Kommentar Ruby-Skript von einem Freund von mir. Wenn Sie das Skript verbessern möchten, können Sie es unter dem Link aktualisieren.
Beachten Sie zunächst, dass Ruby, wenn es eine Shell aufruft, normalerweise aufruft /bin/sh
, nicht Bash. Einige Bash-Syntax wird von nicht unterstützt /bin/sh
auf allen Systemen.
Hier sind Möglichkeiten, ein Shell-Skript auszuführen:
cmd = "echo 'hi'" # Sample string that can be used
Kernel#`
, allgemein Backticks genannt - `cmd`
Dies ist wie viele andere Sprachen, einschließlich Bash, PHP und Perl.
Gibt das Ergebnis 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 dem x
Zeichen ist ein Trennzeichen, das ein beliebiges Zeichen sein kann.
Wenn das Trennzeichen eines der Zeichen ist (
, [
, {
, oder <
,
das Literal besteht aus den Zeichen bis zum passenden schließenden Begrenzer,
Berücksichtigung geschachtelter Delimiter-Paare. Für alle anderen Trennzeichen gilt
Literal umfasst die Zeichen bis zum nächsten Auftreten des
Trennzeichen. String-Interpolation #{ ... }
ist erlaubt.
Gibt das Ergebnis des Shell-Befehls zurück, genau wie die Backticks.
Dokumente: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
value = %x( echo 'hi' )
value = %x[ #{cmd} ]
Kernel#system
Führt den angegebenen Befehl in einer Subshell aus.
Kehrt zurück true
Wenn der Befehl gefunden wurde und erfolgreich ausgeführt wurde, false
Andernfalls.
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 Ausführen des angegebenen externen Befehls.
Gibt keine zurück, der aktuelle Prozess wird ersetzt und wird nie 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 einige zusätzliche Ratschläge:
$?
, das ist das gleiche wie $CHILD_STATUS
, greift auf den Status des letzten vom System ausgeführten Befehls zu, wenn Sie die Backticks verwenden, system()
oder %x{}
.
Sie können dann auf die exitstatus
und pid
Eigenschaften:
$?.exitstatus
Für mehr lesen siehe:
Die Art, wie ich das mache, ist die Verwendung der %x
Literal, was es einfach (und lesbar!) macht, Anführungszeichen in einem Befehl zu verwenden:
directorylist = %x[find . -name '*test.rb' | sort]
In diesem Fall füllt die Dateiliste alle Testdateien im aktuellen Verzeichnis, die Sie wie erwartet verarbeiten können:
directorylist.each do |filename|
filename.chomp!
# work with file
end
Hier ist ein Flussdiagramm basierend auf diese Antwort. Siehe auch, verwenden script
ein Terminal zu emulieren.
Hier ist der beste Artikel meiner Meinung nach zum Ausführen von Shell-Skripten in Ruby: "6 Möglichkeiten zum Ausführen von Shell-Befehlen in Ruby".
Wenn Sie nur die Ausgabe benötigen, verwenden Sie Backticks.
Ich brauchte fortgeschrittenere Sachen wie STDOUT und STDERR, also benutzte ich das Open4-Juwel. Sie haben alle Methoden dort erklärt.
Mein Favorit ist Öffnen3
require "open3"
Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
Einige Dinge, über die Sie bei der Wahl zwischen diesen Mechanismen nachdenken sollten, sind:
Sie können etwas von einfachen Backticks (``), System () und IO.popen
zu ausgewachsen Kernel.fork
/Kernel.exec
mit IO.pipe
und IO.select
.
Sie können auch Timeouts in die Mischung werfen, wenn ein Unterprozess zu lange dauert.
Leider sehr viel hängt davon ab.
Eine weitere Option:
Wenn du:
Sie können die Shell-Umleitung verwenden:
puts %x[cat bogus.txt].inspect
=> ""
puts %x[cat bogus.txt 2>&1].inspect
=> "cat: bogus.txt: No such file or directory\n"
Das 2>&1
Syntax funktioniert übergreifend Linux, Mac und Windows seit den frühen Tagen von MS-DOS.
Ich bin definitiv kein Ruby-Experte, aber ich werde es versuchen:
$ irb
system "echo Hi"
Hi
=> true
Sie sollten auch in der Lage sein, Dinge zu tun wie:
cmd = 'ls'
system(cmd)
Die obigen Antworten sind schon ziemlich gut, aber ich möchte den folgenden zusammenfassenden Artikel wirklich teilen: "6 Möglichkeiten zum Ausführen von Shell-Befehlen in Ruby"
Im Grunde sagt es uns:
Kernel#exec
:
exec 'echo "hello $HOSTNAME"'
system
und $?
:
system 'false'
puts $?
Backticks (`):
today = `date`
IO#popen
:
IO.popen("date") { |f| puts f.gets }
Open3#popen3
- stdlib:
require "open3"
stdin, stdout, stderr = Open3.popen3('dc')
Open4#popen4
-- ein Edelstein:
require "open4"
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Wenn Sie wirklich Bash brauchen, per Note in der "besten" Antwort.
Beachten Sie zunächst, dass Ruby, wenn es eine Shell aufruft, normalerweise aufruft
/bin/sh
, nicht Bash. Einige Bash-Syntax wird von nicht unterstützt/bin/sh
auf allen Systemen.
Wenn Sie Bash verwenden müssen, fügen Sie ein bash -c "your Bash-only command"
innerhalb Ihrer gewünschten Anrufmethode.
quick_output = system("ls -la")
quick_bash = system("bash -c 'ls -la'")
Zu testen:
system("echo $SHELL")
system('bash -c "echo $SHELL"')
Oder wenn Sie eine vorhandene Skriptdatei (z. B. script_output = system("./my_script.sh")
) Rubin sollte ehre den Shebang, aber du könntest immer benutzen system("bash ./my_script.sh")
um sicher zu gehen (obwohl es vielleicht einen leichten Overhead von /bin/sh
Laufen /bin/bash
Das wirst du wahrscheinlich nicht bemerken.