Frage

Wenn ich rufe einen Befehl Kernel # System in Ruby, wie bekomme ich seinen Ausgang?

system("ls")
War es hilfreich?

Lösung

Ich möchte Chaos Antwort ein wenig erweitern und zu klären.

Wenn Sie Ihren Befehl mit Backticks umgeben, dann brauchen Sie nicht (explizit) Rufsystem () überhaupt. Die Backticks den Befehl auszuführen, und die Ausgabe als Zeichenfolge zurück. Anschließend können Sie den Wert einer Variablen zuweisen wie folgt:

output = `ls`
p output

oder

printf output # escapes newline chars

Andere Tipps

Bitte beachten Sie, dass alle Lösungen, bei denen Sie einen String mit Benutzer bereitgestellten Werte übergeben system, %x[] usw. sind unsicher! Unsichere eigentlich bedeutet:. Der Benutzercode auslösen kann im Rahmen und mit allen Berechtigungen des Programms ausführen

Soweit ich nur system und Open3.popen3 tun bieten eine sichere / entweichende Variante in Ruby 1.8 sagen kann. In Ruby 1.9 IO::popen akzeptiert auch ein Array.

Sie einfach alle Optionen übergeben und das Argument als ein Array zu einem dieser Anrufe.

Wenn Sie nicht nur den Exit-Status, sondern auch das Ergebnis, das Sie wollen wahrscheinlich Open3.popen3 verwenden:

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
stdout.gets(nil)
stdout.close
stderr.gets(nil)
stderr.close
exit_code = wait_thr.value

Beachten Sie, dass die Blockform wird automatisch geschlossen stdin, stdout und stderr- sonst würden sie sein müssen geschlossen explizit.

Weitere Informationen finden Sie hier: Forming Sanitär Shell-Befehle oder Systemaufrufe in Ruby

Nur für das Protokoll, wenn sowohl (Ausgabe und Operationsergebnis) möchten, können Sie tun:

output=`ls no_existing_file` ;  result=$?.success?

Der einfache Weg, um dies richtig zu tun und ist sicher zu verwenden, Open3.capture2() , Open3.capture3() .

Mit Rubys Backticks und seine %x alias sind unter keinen Umständen SICHERE , wenn mit nicht vertrauenswürdigen Daten verwendet. Es ist DANGEROUS , schlicht und einfach:

untrusted = "; date; echo"
out = `echo #{untrusted}`                              # BAD

untrusted = '"; date; echo"'
out = `echo "#{untrusted}"`                            # BAD

untrusted = "'; date; echo'"
out = `echo '#{untrusted}'`                            # BAD

Die system Funktion im Gegensatz entkommt Argumente richtig , wenn es richtig verwendet:

ret = system "echo #{untrusted}"                       # BAD
ret = system 'echo', untrusted                         # good

Das Problem ist, gibt es den Exit-Code anstelle des Ausgangs, und diese Erfassung ist verworren und chaotisch.

Die beste Antwort in diesem Thread bisher erwähnt Open3, aber nicht die Funktionen, die für die jeweilige Aufgabe am besten geeignet sind. Open3.capture2, capture2e und capture3 Arbeit wie system, gibt aber zwei oder drei Argumente:

out, err, st = Open3.capture3("echo #{untrusted}")     # BAD
out, err, st = Open3.capture3('echo', untrusted)       # good
out_err, st  = Open3.capture2e('echo', untrusted)      # good
out, st      = Open3.capture2('echo', untrusted)       # good
p st.exitstatus

Ein weiterer erwähnt IO.popen() . Die Syntax kann in dem Sinne ungeschickt sein, dass es ein Array als Eingabe will, aber es funktioniert auch:

out = IO.popen(['echo', untrusted]).read               # good

Der Einfachheit halber können Sie Open3.capture3() in einer Funktion wickeln, z.

#
# Returns stdout on success, false on failure, nil on error
#
def syscall(*cmd)
  begin
    stdout, stderr, status = Open3.capture3(*cmd)
    status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol
  rescue
  end
end

Beispiel:

p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

ergibt die folgende:

nil
nil
false
false
/usr/bin/which         <— stdout from system('which', 'which')
true                   <- p system('which', 'which')
"/usr/bin/which"       <- p syscall('which', 'which')

Sie können mit system () oder% x [] abhängig, welche Art von Ergebnis, das Sie benötigen.

system () gibt true zurück, wenn der Befehl gefunden wurde und lief erfolgreich, ansonsten false.

>> s = system 'uptime'
10:56  up 3 days, 23:10, 2 users, load averages: 0.17 0.17 0.14
=> true
>> s.class
=> TrueClass
>> $?.class
=> Process::Status

% x [..] auf der anderen Seite speichert die Ergebnisse des Befehls als String:

>> result = %x[uptime]
=> "13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> p result 
"13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> result.class
=> String

Blog-Eintrag von Jay Felder erklärt im Detail die Unterschiede zwischen der Verwendung von System, exec und% x [..].

Wenn Sie die Argumente entkommen müssen, in Ruby 1.9 IO. popen akzeptiert auch ein Array:

p IO.popen(["echo", "it's escaped"]).read

In früheren Versionen können Sie Open3 verwenden .popen3 :

require "open3"

Open3.popen3("echo", "it's escaped") { |i, o| p o.read }

Wenn Sie auch stdin übergeben müssen, sollte dies sowohl in 1.9 arbeiten und 1.8:

out = IO.popen("xxd -p", "r+") { |io|
    io.print "xyz"
    io.close_write
    io.read.chomp
}
p out # "78797a"

Sie verwenden Backticks:

`ls`

Eine andere Möglichkeit ist:

f = open("|ls")
foo = f.read()

Beachten Sie, dass die „Rohr“ Zeichen vor „ls“ in geöffnet sind. Dies kann auch Daten verwendet werden, um zu fließen in die Programme der Standardeingabe sowie die Standardausgabe zu lesen.

Ich fand, dass die folgenden nützlich, wenn Sie den Rückgabewert benötigen:

result = %x[ls]
puts result

Ich wollte speziell die PIDs aller Java-Prozesse auf meinem Rechner aufzulisten, und verwendet diese:

ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]

Wie Simon Hürlimann bereits erklärt Open3 ist sicherer als Backtick usw.

require 'open3'
output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }

Beachten Sie, dass die Blockform wird automatisch geschlossen stdin, stdout und stderr- sonst würden sie sein müssen geschlossen explizit .

Während Backticks oder popen verwenden ist oft das, was Sie wirklich wollen, ist es nicht wirklich beantwortet die Frage gestellt. Es kann gute Gründe sein für die Erfassung system Ausgabe (vielleicht für automatisiertes Testen). Ein wenig googeln drehte eine Antwort ich oben dachte, ich würde hier zum Wohl des anderen zu stellen.

Da ich dies nötig für mein Beispiel Testen verwendet einen Block-Setup die Standardausgabe zu erfassen, da der tatsächliche system Aufruf im Code begraben getestet wird:

require 'tempfile'

def capture_stdout
  stdout = $stdout.dup
  Tempfile.open 'stdout-redirect' do |temp|
    $stdout.reopen temp.path, 'w+'
    yield if block_given?
    $stdout.reopen stdout
    temp.read
  end
end

Diese Methode erfaßt jede Ausgabe in dem gegebenen Block ein tempfile mit den tatsächlichen Daten zu speichern. Beispiel für die Verwendung:

captured_content = capture_stdout do
  system 'echo foo'
end
puts captured_content

Sie können den system Anruf mit etwas ersetzen, das intern system nennt. Sie könnten auch ein ähnliches Verfahren verwenden stderr zu erfassen, wenn man will.

Wenn Sie die Ausgabe in eine Datei mit Kernel#system umgeleitet möchten, können Sie Deskriptoren wie folgt ändern Sie:

umleiten stdout und stderr in eine Datei (/ tmp / log) im Append-Modus:

system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])

Für einen langen laufenden Befehl, diese speichert die Ausgabe in Echtzeit. Sie können auch, speichern Sie die Ausgabe eines IO.pipe mit und von Kernel # System umleiten.

Als ein direktes System (...) Ersatz Sie Open3.popen3 verwenden kann (...)

Eine weitere Diskussion: http://tech.natemurray.com/2007/03/ruby-shell -commands.html

Ich habe nicht diesen hier finden, so das Hinzufügen es, ich hatte einige Probleme, die volle Leistung zu bekommen.

  

Sie können STDERR zu STDOUT umleiten, wenn Sie STDERR aufnehmen möchten, verwenden   Graviszeichen.

     

output = `grep Hosts / private / etc / * 2> & 1 '

Quelle: http: // blog .bigbinary.com / 2012/10/18 / Graviszeichen-System-exec-in-ruby.html

puts `date`
puts $?


Mon Mar  7 19:01:15 PST 2016
pid 13093 exit 0
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top