Domanda

Se io chiamo un comando utilizzando kernel del sistema # in Ruby, come faccio a ottenere la sua uscita?

system("ls")
È stato utile?

Soluzione

Mi piacerebbe ampliare e chiarire la risposta di caos un po '.

Se vi circondano il vostro comando con apici inversi, allora non è necessario (esplicitamente) sistema di chiamata () a tutti. Backticks eseguire il comando e restituiscono l'output come stringa. È quindi possibile assegnare il valore di una variabile in questo modo:

output = `ls`
p output

o

printf output # escapes newline chars

Altri suggerimenti

Si tenga presente che tutte le soluzioni in cui si passa una stringa contenente i valori utente fornite system, %x[] ecc sono sicuri! Unsafe significa in realtà:. L'utente può attivare il codice per l'esecuzione in contesto e con tutte le autorizzazioni del programma

Per quanto posso solo dire system e Open3.popen3 forniscono un / variante sicura fuga in Ruby 1.8. In Ruby 1.9 IO::popen accetta anche un array.

È sufficiente passare ogni opzione e l'argomento come una matrice a una di queste chiamate.

Se non è necessario solo lo stato di uscita, ma anche il risultato probabilmente si desidera utilizzare Open3.popen3:

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

Si noti che il modulo di blocco Auto-chiude stdin, stdout e stderr- altrimenti avrebbero dovuto essere ha chiuso in modo esplicito .

Ulteriori informazioni qui: Forming comandi shell igienici o chiamate di sistema in Ruby

Per la cronaca, se si desidera che sia (risultato di uscita e funzionamento) si può fare:

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

Il modo più semplice per farlo correttamente e in modo sicuro è quello di utilizzare Open3.capture2() , Open3.capture2e() , o Open3.capture3() .

usando backticks di Ruby e le sue alias %x sono NON SICURO IN NESSUN CASO se utilizzate con i dati non attendibili. E ' PERICOLOSO , puro e semplice:

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

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

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

La funzione system, al contrario, sfugge argomenti correttamente Se usato correttamente :

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

Il problema è, restituisce il codice di uscita al posto della produzione, e catturando il secondo è contorto e disordinato.

La migliore risposta in questo thread menziona finora Open3, ma non le funzioni che sono più adatti per l'attività. Open3.capture2, capture2e e il lavoro capture3 come system, ma restituisce due o tre argomenti:

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

Un altro menzioni IO.popen() . La sintassi può essere goffo, nel senso che vuole una matrice come input, ma funziona ugualmente:

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

Per comodità, si può avvolgere Open3.capture3() in una funzione, per esempio.

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

Esempio:

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

si ottengono i seguenti:

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

È possibile utilizzare il sistema () o% x [] a seconda di che tipo di risultato che si ha bisogno.

Sistema () restituendo true se il comando è stato trovato e ha funzionato con successo, altrimenti 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 [..] D'altra parte salva i risultati del comando come una stringa:

>> 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 da Jay Campi spiega in dettaglio le differenze tra l'utilizzo del sistema, exec e% x [..].

Se avete bisogno di sfuggire gli argomenti, in Ruby 1.9 IO. popen accetta anche un array:

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

Nelle versioni precedenti è possibile utilizzare Open3 .popen3 :

require "open3"

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

Se hai bisogno anche di passare stdin, questo dovrebbe funzionare in entrambi i 1.9 e 1.8:

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

Si utilizza backticks:

`ls`

Un altro modo è:

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

Si noti che è il carattere "pipe" prima "ls" in aperto. Questo può anche essere utilizzato per alimentare i dati dentro lo standard input programmi così come la lettura suo standard output.

Ho trovato che il seguente è utile se è necessario il valore di ritorno:

result = %x[ls]
puts result

ho espressamente voluto elencare i PID di tutti i processi Java sulla mia macchina, e usato questo:

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

Simon Hürlimann già spiegato , Open3 è più sicuro di backticks ecc

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

Si noti che il modulo di blocco Auto-chiude stdin, stdout e stderr- altrimenti avrebbero dovuto essere chiusi esplicitamente .

Durante l'utilizzo di apici inversi o popen è spesso ciò che si vuole veramente, ma in realtà non rispondere alla domanda posta. Ci possono essere motivi validi per la cattura di uscita system (forse per il test automatizzato). Un po 'Googling alzato una risposta I ho pensato di postare qui per il bene degli altri.

Dato che serviva questo per testare il mio esempio utilizza una configurazione di blocco per catturare l'output standard poiché la chiamata system effettivo è sepolto nel codice in fase di test:

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

Questo metodo cattura qualsiasi uscita nel blocco determinato utilizzando un tempfile per memorizzare i dati effettivi. Esempio di utilizzo:

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

È possibile sostituire la chiamata system con tutto ciò che chiama internamente system. Si potrebbe anche usare un metodo simile per catturare stderr se si voleva.

Se si desidera che l'output reindirizzato a un file utilizzando Kernel#system, si può fare modificare descrittori come questo:

reindirizzare stdout e stderr in un file (/ tmp / log) in accodamento:

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

Per un comando di lunga esecuzione, questo sarà memorizzare l'output in tempo reale. Si può anche, memorizzare l'output utilizzando un IO.pipe e reindirizzare dal kernel del sistema #.

Come sistema diretta (...) la sostituzione è possibile utilizzare Open3.popen3 (...)

Ulteriore discussione: http://tech.natemurray.com/2007/03/ruby-shell -commands.html

non ho trovato questo qui in modo da aggiungere, ho avuto alcuni problemi di ottenere la piena potenza.

  

È possibile reindirizzare STDERR a STDOUT se si desidera catturare STDERR usando   backtick.

     

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

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

puts `date`
puts $?


Mon Mar  7 19:01:15 PST 2016
pid 13093 exit 0
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top