web-dev-qa-db-fra.com

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

Est-il possible d'exécuter des commandes en ligne de commande via Ruby? J'essaie de créer un petit programme Ruby) qui composerait et recevrait/enverrait via des programmes en ligne de commande tels que 'screen', 'rcsz', etc.

Ce serait formidable de pouvoir lier tout cela avec Ruby (backend MySQL, etc.)

89
geetfun

Oui. Il y a plusieurs façons:


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 la sortie standard 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 true si la commande a abouti. 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 en cours par celui créé par la commande.


d. (Ruby 1.9) utilise 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 la fin du processus 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 objet IO qui représente les entrées/sorties des nouveaux processus. C'est aussi actuellement le seul moyen que je connaisse pour apporter une contribution au programme.


f. Utilisez Open3 (le 1.9.2 et les 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

Open3 possède plusieurs autres fonctions pour obtenir un accès explicite aux deux flux de sortie. Cela ressemble à popen, mais vous donne accès à stderr.

203
Adrian

Il y a 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 des entrées et des sorties avec les commandes stdin/stdout de la commande, vous voudrez probablement regarder IO::popen méthode, qui propose spécifiquement cette fonctionnalité.

14
Mark Rushakoff
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output
7
ohho

Oui, cela 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 backticks standard et/ou les appels system/exec.

Si le programme fonctionne en mode "Plein écran" comme écran ou vi, l'approche doit être différente. Pour de tels programmes, vous devriez rechercher une implémentation Ruby de la bibliothèque "expect". Cela vous permettra de scripter ce que vous attendez à l'écran et ce qu'il faut envoyer lorsque vous voyez ces chaînes particulières. apparaissent à 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/gem appropriée pour le faire plutôt que d'essayer d'automatiser une application plein écran existante. Par exemple, " Besoin d'aide pour les communications par port série en Ruby " traite des communications par port série, un précurseur de numérotation si c'est ce que vous voulez réaliser à l'aide des programmes spécifiques que vous avez mentionnés.

2
Steve Weet

La méthode la plus utilisée utilise Open3 voici ma version modifiée 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
0
Keshav Maheshwari