Exécution de commandes de ligne de commande dans le script Ruby

92

Existe-t-il un moyen d'exécuter des commandes de ligne de commande via Ruby? J'essaie de créer un petit programme Ruby qui composerait et recevrait / enverrait via des programmes de ligne de commande comme 'screen', 'rcsz', etc.

Ce serait formidable si je pouvais lier tout cela avec Ruby (backend MySQL, etc.)

geetfun
la source
Copie

Réponses:

209

Oui. Il existe plusieurs manières:


une. Utilisez %xou '' ':

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

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

Ces méthodes renverront le stdout et redirigeront stderr vers le programme.


b. Utilisez system:

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

Cette méthode retourne truesi la commande a réussi. Il redirige toute la sortie vers le programme.


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

Cela remplace le processus actuel par celui créé par la commande.


ré. (ruby 1.9) utiliser spawn:

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

Cette méthode n'attend pas que le processus se termine et renvoie le PID.


e. Utilisez IO.popen:

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

Cette méthode retournera un IOobjet qui représente l'entrée / sortie des nouveaux processus. C'est aussi actuellement le seul moyen que je connaisse pour donner une contribution au programme.


F. Utiliser Open3(sur 1.9.2 et versions ultérieures)

require 'open3'

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

Open3a plusieurs autres fonctions pour obtenir un accès explicite aux deux flux de sortie. C'est similaire à popen, mais vous donne accès à stderr.

Adrian
la source
Trick Bonus: io = IO.popen 'cat > out.log', 'r+'; écrit les sorties de la commande dans "out.log"
Narfanator
1
Quels sont les avantages et les inconvénients de chacun. Comment décider lequel utiliser? Que diriez-vous d'utiliser FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava
1
J'exécute une commande SVN en utilisant exec. Je ne veux pas que la sortie de exec apparaisse sur la console. Je veux le rediriger afin que je puisse le stocker en tant que variable et faire un traitement à ce sujet. Comment fait-on ça ?
stack1
2
status.successful? ne fonctionne plus pour moi sur ruby ​​2.4, il est passé à status.success? :)
DanielG
14

Il existe plusieurs façons d'exécuter des commandes système dans 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"

Mais si vous devez réellement effectuer une entrée et une sortie avec la commande stdin / stdout, vous voudrez probablement regarder la IO::popenméthode, qui offre spécifiquement cette fonctionnalité.

Mark Rushakoff
la source
popen fonctionne bien si votre application n'a qu'une sortie standard. Si vous avez besoin de plus d'interaction ou si vous voulez faire quelque chose de différent avec stdout, stdin et en particulier stderr, vous voudrez également vous pencher sur open3: ruby-doc.org/core/classes/Open3.html
Paul Rubel
7
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output
ohho
la source
2

Oui, c'est certainement faisable mais la méthode de mise en œuvre diffère selon que le programme "ligne de commande" en question fonctionne en mode "plein écran" ou en ligne de commande. Les programmes écrits pour la ligne de commande ont tendance à lire STDIN et à écrire dans STDOUT. Ceux-ci peuvent être appelés directement dans Ruby en utilisant les méthodes standard de backticks et / ou les appels système / exec.

Si le programme fonctionne en mode "Plein écran" comme screen ou vi, alors l'approche doit être différente. Pour des programmes comme celui-ci, vous devriez rechercher une implémentation Ruby de la bibliothèque "expect". Cela vous permettra de créer un script de ce que vous vous attendez à voir à l'écran et de ce qu'il faut envoyer lorsque vous voyez ces chaînes particulières apparaître à l'écran.

Il est peu probable que ce soit la meilleure approche et vous devriez probablement regarder ce que vous essayez d'atteindre et trouver la bibliothèque / gemme appropriée pour le faire plutôt que d'essayer d'automatiser une application plein écran existante. À titre d'exemple, « Besoin d'aide pour les communications du port série dans Ruby » traite des communications du port série, un précurseur à la numérotation si c'est ce que vous voulez réaliser en utilisant les programmes spécifiques que vous avez mentionnés.

Steve Weet
la source
Une version simple d'Expect est disponible dans Ruby en utilisant son module Pty intégré.
The Tin Man
0

La méthode la plus utilisée utilise Open3ici est ma version éditée par le code du code ci-dessus avec quelques corrections:

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
Keshav Maheshwari
la source