Ausführen von Befehlszeilenbefehlen in Ruby-Skripten

92

Gibt es eine Möglichkeit, Befehlszeilenbefehle über Ruby auszuführen? Ich versuche, ein kleines Ruby-Programm zu erstellen, das über Befehlszeilenprogramme wie "screen", "rcsz" usw. wählt und empfängt / sendet.

Es wäre großartig, wenn ich all dies mit Ruby verknüpfen könnte (MySQL-Backend usw.)

geetfun
quelle
Mögliches Duplikat von Calling Shell-Befehlen von Ruby
Ymoreau

Antworten:

209

Ja. Es gibt verschiedene Möglichkeiten:


ein. Verwenden Sie %xoder '`':

%x(echo hi) #=> "hi\n"
%x(echo hi >&2) #=> "" (prints 'hi' to stderr)

`echo hi` #=> "hi\n"
`echo hi >&2` #=> "" (prints 'hi' to stderr)

Diese Methoden geben das stdout zurück und leiten stderr zum Programm um.


b. Verwendung system:

system 'echo hi' #=> true (prints 'hi')
system 'echo hi >&2' #=> true (prints 'hi' to stderr)
system 'exit 1' #=> nil

Diese Methode wird zurückgegeben, truewenn der Befehl erfolgreich war. Es leitet alle Ausgaben an das Programm weiter.


c. Verwendung exec:

fork { exec 'sleep 60' } # you see a new process in top, "sleep", but no extra ruby process. 
exec 'echo hi' # prints 'hi'
# the code will never get here.

Dadurch wird der aktuelle Prozess durch den vom Befehl erstellten ersetzt.


d. (Rubin 1.9) verwenden spawn:

spawn 'sleep 1; echo one' #=> 430
spawn 'echo two' #=> 431
sleep 2
# This program will print "two\none".

Diese Methode wartet nicht auf das Beenden des Prozesses und gibt die PID zurück.


e. Verwendung IO.popen:

io = IO.popen 'cat', 'r+'
$stdout = io
puts 'hi'
$stdout = IO.new 0
p io.read(1)
io.close
# prints '"h"'.

Diese Methode gibt ein IOObjekt zurück, das die Eingabe / Ausgabe der neuen Prozesse darstellt. Es ist derzeit auch die einzige mir bekannte Möglichkeit, die Programmeingabe zu geben.


f. Verwenden Sie Open3(ab 1.9.2)

require 'open3'

stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.successful?
  puts stdout
else
  STDERR.puts "OH NO!"
end

Open3verfügt über mehrere andere Funktionen, um expliziten Zugriff auf die beiden Ausgabestreams zu erhalten. Es ist ähnlich wie Popen, gibt Ihnen aber Zugriff auf stderr.

Adrian
quelle
Bonus-Trick : io = IO.popen 'cat > out.log', 'r+'; schreibt die Ausgaben des Befehls in "out.log"
Narfanator
1
Was sind die Vor- und Nachteile für jeden. Wie entscheide ich mich für eine Verwendung? Wie wäre es mit FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava
1
Ich führe einen SVN-Befehl mit exec aus. Ich möchte nicht, dass die Ausgabe von exec auf der Konsole angezeigt wird. Ich möchte es umleiten, damit ich es als Variable speichern und etwas verarbeiten kann. Wie mache ich es ?
Stack1
2
status.successful? funktioniert bei ruby ​​2.4 nicht mehr für mich, es wurde in status.success geändert? :)
DanielG
14

Es gibt verschiedene Möglichkeiten, Systembefehle in Ruby auszuführen.

irb(main):003:0> `date /t` # surround with backticks
=> "Thu 07/01/2010 \n"
irb(main):004:0> system("date /t") # system command (returns true/false)
Thu 07/01/2010
=> true
irb(main):005:0> %x{date /t} # %x{} wrapper
=> "Thu 07/01/2010 \n"

Wenn Sie jedoch tatsächlich Ein- und Ausgaben mit dem Befehl stdin / stdout ausführen müssen, sollten Sie sich wahrscheinlich die IO::popenMethode ansehen , die diese Funktion speziell bietet.

Mark Rushakoff
quelle
popen funktioniert gut, wenn Ihre App nur Standard hat. Wenn Sie mehr Interaktion benötigen oder etwas anderes mit stdout, stdin und insbesondere stderr machen möchten, sollten Sie sich auch open3 ansehen: ruby-doc.org/core/classes/Open3.html
Paul Rubel
7
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output
Oh ho
quelle
2

Ja, dies ist sicherlich machbar, aber die Implementierungsmethode hängt davon ab, ob das betreffende "Befehlszeilen" -Programm im "Vollbild" - oder im Befehlszeilenmodus ausgeführt wird. Für die Befehlszeile geschriebene Programme neigen dazu, STDIN zu lesen und in STDOUT zu schreiben. Diese können mithilfe der Standard-Backticks-Methoden und / oder System- / Exec-Aufrufe direkt in Ruby aufgerufen werden.

Wenn das Programm im "Vollbild" -Modus wie Bildschirm oder vi arbeitet, muss der Ansatz anders sein. Für Programme wie dieses sollten Sie nach einer Ruby-Implementierung der "Expect" -Bibliothek suchen. Auf diese Weise können Sie skripten, was Sie auf dem Bildschirm erwarten und was gesendet werden soll, wenn diese bestimmten Zeichenfolgen auf dem Bildschirm angezeigt werden.

Dies ist wahrscheinlich nicht der beste Ansatz, und Sie sollten sich wahrscheinlich ansehen, was Sie erreichen möchten, und die entsprechende Bibliothek / das Juwel finden, um dies zu tun, anstatt zu versuchen, eine vorhandene Vollbildanwendung zu automatisieren. Als Beispiel behandelt " Benötigen Sie Unterstützung bei der Kommunikation über serielle Schnittstelle in Ruby " die Kommunikation über serielle Schnittstelle , ein Vorläufer für das Wählen, wenn Sie dies mit den von Ihnen genannten spezifischen Programmen erreichen möchten.

Steve Weet
quelle
Eine einfache Version von Expect ist in Ruby mithilfe des integrierten Pty- Moduls verfügbar .
der Blechmann
0

Die am häufigsten verwendete Methode ist Open3Hier ist meine Code-bearbeitete Version des obigen Codes mit einigen Korrekturen:

require 'open3'
puts"Enter the command for execution"
some_command=gets
stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.success?
  puts stdout
else
  STDERR.puts "ERRRR"
end
Keshav Maheshwari
quelle