2010-07-01 16 views
76

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

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

Répondre

13

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 effectuer réellement entrée et de sortie avec stdin/stdout de la commande, vous aurez probablement envie de regarder la méthode IO::popen, qui offre spécifiquement cette installation.

+0

popen fonctionne bien si votre application a juste la sortie standard. Si vous avez besoin de plus d'interaction ou que vous voulez faire quelque chose de différent avec stdout, stdin, et en particulier stderr, vous voudrez aussi regarder dans open3: http://ruby-doc.org/core/classes/Open3.html –

180

Oui. Il y a plusieurs manières:


a. Utilisez %x ou '`':

%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 rediriger stderr vers ce programme.


b. utilisation system:

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

Cette méthode retourne true si la commande a réussi. Il redirige toutes les sorties vers le programme.


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

qui remplace le processus actuel avec celui créé par la commande.


d. (Ruby 1.9) utilisent 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 pour le processus de sortie et retourne le PID.


e. utilisation 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 retourne un objet IO que reperesents d'entrée/sortie des nouveaux procédés. C'est aussi actuellement la seule façon dont je sais de donner la contribution du programme.


f. Utiliser Open3 (le 1.9.2 et plus tard)

require 'open3' 

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

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

+0

Résumé brillant Adrian , Merci d'avoir partagé cette information. – KomodoDave

+0

Astuce: 'io = IO.popen 'cat> out.log', 'r +''; écrit les sorties de la commande à "out.log" – Narfanator

+1

Quels sont les avantages et les inconvénients de chacun. Comment puis-je décider lequel utiliser? Que diriez-vous d'utiliser 'FileUtils' [http://ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html]? – Ava

2

Oui, c'est certainement faisable mais la méthode d'implémentation diffère selon que le programme "ligne de commande" en question fonctionne en mode "Plein écran" ou 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 backticks standard et/ou les appels system/exec.

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

Il est peu probable que ce soit la meilleure approche et vous devriez probablement regarder ce que vous essayez d'obtenir et trouver la bibliothèque/gemme appropriée pour le faire plutôt que d'essayer d'automatiser une application en plein écran existante. Par exemple, "Need assistance with serial port communications in Ruby" traite des communications de port série, un précurseur de numérotation si c'est ce que vous voulez réaliser en utilisant les programmes spécifiques que vous avez mentionnés.

+0

Une version simple d'Expect est disponible dans Ruby en utilisant son module intégré [Pty] (http://www.ruby-doc.org/stdlib-1.9.3/libdoc/pty/rdoc/PTY.html) . –

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

La méthode utilisée est plus Open3 Utilisation voici ma version modifiée du 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