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?Bei der Wahl zwischen diesen Mechanismen sind einige Dinge zu bedenken:
- Wollen Sie nur stdout oder wollen Sie auch stderr benötigen? Oder sogar herausgetrennt?
- Wie groß ist Ihr Output? Wollen Sie das gesamte Ergebnis im Speicher halten?
- Möchten Sie einige Ihrer Ausgabe lesen, während der Unterprozess noch läuft?
- Benötigen Sie Ergebniscodes?
- Benötigen Sie ein Ruby-Objekt, das den Prozess repräsentiert und mit dem Sie bei Bedarf beenden kann?
Sie können alles von einfachen Backticks (``) benötigen, system()
y IO.popen
zu einer ausgewachsenen Kernel.fork
/ Kernel.exec
con IO.pipe
y IO.select
.
Sie können auch Timeouts einbauen, wenn ein Unterprozess zu lange für die Ausführung braucht.
Leider ist es sehr viel hängt .
Eine weitere Möglichkeit:
Wenn Sie:
- sowohl stderr als auch stdout benötigen
- kann/will Open3/Open4 nicht verwenden (sie lösen in NetBeans auf meinem Mac Ausnahmen aus, keine Ahnung warum)
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"
El 2>&1
Syntax funktioniert über Linux , Mac und Windows seit den frühen Tagen von MS-DOS.
Die obigen Antworten sind bereits sehr gut, aber ich möchte den folgenden zusammenfassenden Artikel unbedingt teilen: " 6 Möglichkeiten, Shell-Befehle in Ruby auszuführen "
Im Grunde sagt sie uns das:
Kernel#exec
:
exec 'echo "hello $HOSTNAME"'
system
y $?
:
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 Juwel:
require "open4"
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Wenn Sie Bash wirklich brauchen, beachten Sie den Hinweis in der "besten" Antwort.
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.
Wenn Sie die Bash verwenden müssen, fügen Sie bash -c "your Bash-only command"
innerhalb der von Ihnen gewünschten Aufrufmethode:
quick_output = system("ls -la")
quick_bash = system("bash -c 'ls -la'")
Zum Testen:
system("echo $SHELL")
system('bash -c "echo $SHELL"')
Oder wenn Sie eine bestehende Skriptdatei ausführen wie
script_output = system("./my_script.sh")
Rubinrot debe die ganze Sache zu würdigen, aber Sie können auch
system("bash ./my_script.sh")
um sicher zu gehen, obwohl es einen leichten Mehraufwand durch /bin/sh
läuft /bin/bash
werden Sie es wahrscheinlich nicht bemerken.
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 .