Esecuzione di comandi da riga di comando all'interno dello script Ruby


92

C'è un modo per eseguire i comandi della riga di comando tramite Ruby? Sto cercando di creare un piccolo programma Ruby che componga e riceva / invii tramite programmi a riga di comando come 'screen', 'rcsz', ecc.

Sarebbe fantastico se potessi collegare tutto questo con Ruby (backend MySQL, ecc.)


Possibile duplicato di Calling shell commands from Ruby
ymoreau

Risposte:


209

Sì. Esistono diversi modi:


un. Usa %xo '`':

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

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

Questi metodi restituiranno lo stdout e reindirizzeranno lo stderr al programma.


b. Usa system:

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

Questo metodo restituisce truese il comando ha avuto successo. Reindirizza tutto l'output a quello del programma.


c. Usa 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.

Ciò sostituisce il processo corrente con quello creato dal comando.


d. (rubino 1.9) utilizzare spawn:

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

Questo metodo non attende la fine del processo e restituisce il PID.


e. Usa IO.popen:

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

Questo metodo restituirà un IOoggetto che riproduce l'input / output dei nuovi processi. Attualmente è anche l'unico modo che conosco per fornire input al programma.


f. Usa Open3(su 1.9.2 e versioni successive)

require 'open3'

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

Open3ha molte altre funzioni per ottenere l'accesso esplicito ai due flussi di output. È simile a popen, ma ti dà accesso a stderr.


Bonus trucco: io = IO.popen 'cat > out.log', 'r+'; scrive gli output del comando in "out.log"
Narfanator

1
Quali sono i pro ei contro per ciascuno. Come decido quale usare? Che ne dici di usare FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava

1
Sto eseguendo un comando SVN usando exec. Non voglio che l'output di exec appaia sulla console. Voglio reindirizzarlo in modo da poterlo memorizzare come variabile ed eseguire alcune elaborazioni su questo. Come lo faccio ?
stack1

2
status.successful? non funziona più per me su ruby ​​2.4, è cambiato in status.success? :)
DanielG

14

Esistono alcuni modi per eseguire i comandi di sistema in Ruby.

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"

Ma se hai bisogno di eseguire effettivamente input e output con stdin / stdout del comando, probabilmente vorrai guardare il IO::popenmetodo, che offre specificamente quella funzionalità.


popen funziona bene se la tua app ha solo l'uscita standard. Se hai bisogno di più interazioni o vuoi fare qualcosa di diverso con stdout, stdin e in particolare stderr, ti consigliamo di esaminare anche open3
Paul Rubel

7
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output

2

Sì, questo è certamente fattibile, ma il metodo di implementazione differisce a seconda che il programma "riga di comando" in questione funzioni in modalità "Schermo intero" o riga di comando. I programmi scritti per la riga di comando tendono a leggere STDIN e scrivere in STDOUT. Questi possono essere chiamati direttamente in Ruby usando i metodi backtick standard e / o le chiamate system / exec.

Se il programma funziona in modalità "Schermo intero" come schermo o vi, l'approccio deve essere diverso. Per programmi come questo dovresti cercare un'implementazione Ruby della libreria "aspetta". Ciò ti consentirà di scrivere ciò che ti aspetti di vedere sullo schermo e cosa inviare quando vedrai apparire quelle stringhe particolari sullo schermo.

È improbabile che questo sia l'approccio migliore e dovresti probabilmente guardare a ciò che stai cercando di ottenere e trovare la libreria / gemma pertinente per farlo piuttosto che provare ad automatizzare un'applicazione a schermo intero esistente. Ad esempio " Hai bisogno di assistenza con le comunicazioni della porta seriale in Ruby " si occupa delle comunicazioni della porta seriale, un precursore per la composizione se questo è ciò che vuoi ottenere usando i programmi specifici che hai menzionato.


Una semplice versione di Expect è disponibile in Ruby usando il suo modulo Pty integrato.
Tin Man

0

Il metodo più usato sta usando Open3qui è la mia versione modificata del codice del codice sopra con alcune correzioni:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.