it-swarm.com.de

Ausgabe von system () - Aufrufen in Ruby abrufen

Wenn ich einen Befehl mit Kernel # system in Ruby aufrufe, wie erhalte ich seine Ausgabe?

system("ls")
291
Macha

Ich möchte gerne erweitern/klären die Antwort von chaos ein bisschen.

Wenn Sie Ihren Befehl mit Backticks umgeben, müssen Sie system () überhaupt nicht (explizit) aufrufen. Die Backticks führen den Befehl aus und geben die Ausgabe als String zurück. Sie können den Wert dann einer Variablen wie folgt zuordnen:

output = `ls`
p output

oder

printf output # escapes newline chars
333
Craig Walker

Beachten Sie, dass alle Lösungen, bei denen Sie eine Zeichenfolge mit benutzerdefinierten Werten an system, %x[] usw. übergeben, unsicher sind! Unsicher bedeutet eigentlich: Der Benutzer kann auslösen, dass Code im Kontext und mit allen Berechtigungen des Programms ausgeführt wird.

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

Übergeben Sie einfach jede Option und jedes Argument als Array an einen dieser Aufrufe.

Wenn Sie nicht nur den Exit-Status, sondern auch das Ergebnis benötigen, möchten Sie 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 das Blockformular stdin, stdout und stderr automatisch schließt. Andernfalls müssen sie explizit close sein.

Weitere Informationen hier: Bilden von hygienischen Shellbefehlen oder Systemaufrufen in Ruby

228

Nur für die Aufzeichnung, wenn Sie beide (Ausgabe- und Operationsergebnis) möchten, können Sie Folgendes tun:

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

Der einfachste Weg, dies richtig und sicher auszuführen, ist die Verwendung von Open3.capture2() , Open3.capture2e() oder Open3.capture3() .

Rubys Backticks und sein %x-Alias ​​sind NOT SECURE UNTER JEDEN UMSTÄNDEN, wenn sie mit nicht vertrauenswürdigen Daten verwendet werden. Es ist GEFÄHRLICH, 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 entgeht dagegen Argumenten korrekt bei korrekter Verwendung:

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

Das Problem ist, es gibt den Exit-Code anstelle der Ausgabe zurück, und das Erfassen der letzteren ist gefaltet und unordentlich.

Die bisher beste Antwort in diesem Thread erwähnt Open3, jedoch nicht die Funktionen, die für die Aufgabe am besten geeignet sind. Open3.capture2, capture2e und capture3 funktionieren wie system, geben jedoch zwei oder drei Argumente zurück:

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

Weitere Erwähnungen IO.popen() . Die Syntax kann in dem Sinne unbeholfen sein, dass ein Array als Eingabe gewünscht wird, es funktioniert jedoch auch:

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

Der Einfachheit halber können Sie Open3.capture3() in eine Funktion einschließen, 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 folgendes:

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

Sie können system () oder% x [] verwenden, je nachdem, welche Art von Ergebnis Sie benötigen.

system () gibt true zurück, wenn der Befehl gefunden wurde und erfolgreich ausgeführt wurde, andernfalls 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 [..] dagegen speichert die Ergebnisse des Befehls als Zeichenfolge:

>> 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

Der Blogbeitrag von Jay Fields erläutert detailliert die Unterschiede zwischen System, Exec und% x [..].

59
Martin Gross

Ein anderer Weg ist:

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

Beachten Sie, dass dies das Pipe-Zeichen vor "ls" in open ist. Dies kann auch verwendet werden, um Daten in die Standardeingabe des Programms einzugeben und deren Standardausgabe zu lesen.

19
dwc

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

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

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

require "open3"

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

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

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

Sie verwenden Backticks:

`ls`
19
chaos

Ich habe festgestellt, dass Folgendes hilfreich ist, wenn Sie den Rückgabewert benötigen:

result = %x[ls]
puts result

Ich wollte speziell die Pids aller Java-Prozesse auf meinem Rechner auflisten und habe folgendes verwendet:

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

Wie Simon Hürlimann bereits erklärt hat, ist Open3 sicherer als Backticks usw. 

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

Beachten Sie, dass das Blockformular stdin, stdout und stderr automatisch schließt. Andernfalls müssen sie explizit close sein.

11
Yarin

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

umleiten von stdout und stderr zu einer Datei (/ tmp/log) im Anfügemodus:

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

Bei einem langen Befehl wird die Ausgabe in Echtzeit gespeichert. Sie können die Ausgabe auch mit einer IO.pipe speichern und vom Kernel-System umleiten.

8
Ashrith

Die Verwendung von Backticks oder Popens ist zwar oft das, was Sie wirklich wollen, es beantwortet jedoch nicht die gestellte Frage. Es kann stichhaltige Gründe für die Erfassung der system-Ausgabe geben (möglicherweise für automatisiertes Testen). Ein bisschen googeln gab eine Antwort auf Ich dachte, ich würde hier zum Wohle anderer posten. 

Da ich dies zum Testen brauchte, verwendet mein Beispiel eine Blockeinstellung, um die Standardausgabe zu erfassen, da der tatsächliche Aufruf system im getesteten Code enthalten ist:

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 erfasst jede Ausgabe in einem gegebenen Block unter Verwendung einer Servicedatei, um die tatsächlichen Daten zu speichern. Verwendungsbeispiel:

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

Sie können den Aufruf system durch alles ersetzen, das intern system aufruft. Sie können auch eine ähnliche Methode zum Erfassen von stderr verwenden, wenn Sie möchten.

8
Eric Anderson

Als direkter Systemersatz (...) können Sie Open3.popen3 (...) verwenden.

Weitere Diskussion: http://tech.natemurray.com/2007/03/Ruby-Shell-commands.html

7

Ich habe dieses hier nicht gefunden, also habe ich beim Hinzufügen einige Probleme mit dem vollen Output. 

Sie können STDERR nach STDOUT umleiten, wenn Sie STDERR mit .__ erfassen möchten. Backtick.

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

quelle: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-Ruby.html

0
dac2009