1265 Stimmen

Wie man Shell-Befehle aus Ruby aufruft

Wie kann ich Shell-Befehle aus einem Ruby-Programm heraus aufrufen? Wie bekomme ich dann die Ausgabe dieser Befehle zurück in Ruby?

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 modifizierte PATH ( 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 von Open3 .

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 .

13voto

Rufo Sanchez Punkte 605

Sie können auch die Backtick-Operatoren (`) verwenden, ähnlich wie in Perl:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

Praktisch, wenn Sie etwas Einfaches brauchen.

Welche Methode Sie verwenden möchten, hängt davon ab, was Sie genau erreichen wollen. In den Dokumenten finden Sie weitere Informationen zu den verschiedenen Methoden.

12voto

Ryan Tate Punkte 1471

Anhand der hier gegebenen und in Mihais Antwort verlinkten Antworten habe ich eine Funktion erstellt, die diese Anforderungen erfüllt:

  1. Erfasst STDOUT und STDERR, so dass sie nicht "auslaufen", wenn mein Skript über die Konsole ausgeführt wird.
  2. Erlaubt die Übergabe von Argumenten an die Shell als Array, so dass man sich keine Gedanken über Escaping machen muss.
  3. Erfasst den Exit-Status des Befehls, damit klar ist, wann ein Fehler aufgetreten ist.

Als Bonus gibt dieser Befehl auch STDOUT zurück, wenn der Shell-Befehl erfolgreich beendet wird (0) und etwas auf STDOUT ausgibt. Auf diese Weise unterscheidet sie sich von system der einfach Folgendes zurückgibt true in solchen Fällen.

Der Code folgt. Die spezifische Funktion ist system_quietly :

require 'open3'

class ShellError < StandardError; end

#actual function:
def system_quietly(*cmd)
  exit_status=nil
  err=nil
  out=nil
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
    err = stderr.gets(nil)
    out = stdout.gets(nil)
    [stdin, stdout, stderr].each{|stream| stream.send('close')}
    exit_status = wait_thread.value
  end
  if exit_status.to_i > 0
    err = err.chomp if err
    raise ShellError, err
  elsif out
    return out.chomp
  else
    return true
  end
end

#calling it:
begin
  puts system_quietly('which', 'ruby')
rescue ShellError
  abort "Looks like you don't have the `ruby` command. Odd."
end

#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"

12voto

MonsieurDart Punkte 5916

Vergessen Sie nicht die spawn um einen Hintergrundprozess zur Ausführung des angegebenen Befehls zu erstellen. Sie können sogar auf dessen Beendigung warten, indem Sie die Process Klasse und der zurückgegebenen pid :

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

Der Arzt sagt: Diese Methode ist vergleichbar mit #system aber er wartet nicht, bis der Befehl beendet ist.

12voto

nkm Punkte 5746

Wir können dies auf verschiedene Weise erreichen.

Verwendung von Kernel#exec nach der Ausführung dieses Befehls nichts mehr:

exec('ls ~')

Verwendung von backticks or %x

`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"

Verwendung von Kernel#system Befehl, gibt zurück true wenn erfolgreich, false wenn er nicht erfolgreich war und gibt nil wenn die Befehlsausführung fehlschlägt:

system('ls ~')
=> true

10voto

Alex Lorsung Punkte 143

Der einfachste Weg ist zum Beispiel:

reboot = `init 6`
puts reboot

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X