command line ruby

Ruby: 6 façons exécuté des lignes de commandes dans une application Ruby.

Partagez sur:

Parfois on a envie d’inter-agir avec le system d’exploitation ou s’exécute des commandes shell dans notre application Ruby. Ruby fourni plusieurs manières pour faire ces opérations .

Exec

Kernel#exec (ou simplement exec), remplace le processus actuel en exécutant la commande fourni.

Exemple :

$ irb   >> exec 'echo "hello $HOSTNAME"'   hello nate.local   $

Remarquez comment exec remplace le processus irb avec la commande echo qui se ferme ensuite. Parce que le Ruby se termine efficacement, cette méthode n’a qu’une utilisation limitée. L’inconvénient majeur est que vous ne connaissez pas le succès ou l’échec de la commande de votre script Ruby.

System

La commande system fonctionne de manière similaire, mais la commande system s’exécute dans un sous-shell au lieu de remplacer le processus actuel. Cette commande nous donne un peu plus d’informations que exec dans la mesure où il renvoie true si la commande a été exécutée avec succès et false sinon.

$ irb                >> system 'echo "hello $HOSTNAME"'   hello nate.local   => true   >> system 'false'    => false   >> puts $?   256   => nil   >> 

La commande system définit la variable globale $? au statut de sortie du processus. Notez que nous avons le statut de sortie de la commande false (qui se ferme toujours avec un code différent de zéro). Vérifier le code de sortie nous donne l’opportunité de déclencher une exception ou de relancer notre commande.
Note pour les débutants: Les commandes Unix se terminent généralement avec un statut de 0 en cas de succès et différent de zéro sinon.

La commande system est géniale si tout ce que nous voulons savoir est “Est-ce que ma commande a été réussie ou non?” Cependant, nous voulons souvent capturer le résultat de la commande puis utiliser cette valeur dans notre programme.

Backticks (`)

Les Backticks (également appelés «backquotes») exécutent la commande dans un sous-shell et renvoient la sortie standard de cette commande.

$ irb   >> today = `date`   => "Mon Mar 12 18:15:35 PDT 2007\n"    >> $?   => #<Process::Status: pid=25827,exited(0)>   >> $?.to_i   => 0

C’est probablement la méthode la plus utilisée et la plus connue pour exécuter des commandes dans un sous-shell. Comme vous pouvez le constater, ceci est très utile car il retourne le résultat de la commande et peut ensuite être utilisé comme n’importe quelle autre chaîne.

Notez que $? n’est pas simplement un entier du statut de retour mais bien un objet Process :: Status. Nous avons non seulement le statut de sortie mais également l’identifiant du processus. Process :: Status # to_i nous donne le statut de sortie sous forme d’entier (et #to_s nous indique le statut de sortie sous forme de chaîne).

L’utilisation des backticks a pour conséquence que nous n’obtenons que la sortie standard (stdout) de cette commande, mais pas l’erreur standard (stderr). Dans cet exemple, nous exécutons un script Perl qui envoie une chaîne à stderr.

$ irb   >> warning = `perl -e "warn 'dust in the wind'"`   dust in the wind at -e line 1.   => ""    >> puts warning   => nil

Notez que l’avertissement de variable n’est pas défini! Lorsque nous avertissons en Perl, ceci est généré sur stderr et n’est pas capturé par des backticks.

IO#popen

IO#popen est un autre moyen d’exécuter une commande dans un sous-processus. popen vous donne un peu plus de contrôle en ce que l’entrée standard et la sortie standard du sous-processus sont toutes deux connectées à l’objet IO.

$ irb   >> IO.popen("date") { |f| puts f.gets }   Mon Mar 12 18:58:56 PDT 2007   => nil

Bien que IO#popen soit agréable, j’utilise généralement Open3#popen3 lorsque j’ai besoin de ce niveau de granularité.

LIRE AUSSI: Créer une application en ligne de commande en Ruby avec Thor

Open3#popen3

La bibliothèque standard Ruby comprend la classe Open3. Il est facile à utiliser et renvoie stdin, stdout et stderr. Dans cet exemple, utilisons la commande interactive dc. dc est une calculatrice en polonais inversé lue à partir de stdin. Dans cet exemple, nous allons placer deux nombres et un opérateur dans la pile. Ensuite, nous utilisons p pour imprimer le résultat de l’opérateur sur les deux nombres. Ci-dessous, nous appuyons sur 5, 10 et + et obtenons une réponse de 15 \ n à la sortie standard.

$ irb   >> stdin, stdout, stderr = Open3.popen3('dc')    => [#<IO:0x6e5474>, #<IO:0x6e5438>, #<IO:0x6e53d4>]   >> stdin.puts(5)   => nil   >> stdin.puts(10)   => nil   >> stdin.puts("+")   => nil   >> stdin.puts("p")   => nil   >> stdout.gets   => "15\n" 

Notez qu’avec cette commande, non seulement nous lisons le résultat mais nous écrivons également dans le stdin de la commande. Cela nous laisse beaucoup de flexibilité dans le fait que nous pouvons interagir avec la commande si nécessaire.

popen3 nous donnera également le stderr si nous en avons besoin.

# (irb continued...)   >> stdin.puts("asdfasdfasdfasdf")   => nil   >> stderr.gets   => "dc: stack empty\n" 

Cependant, popen3 dans ruby 1.8.5 présente un inconvénient: il ne renvoie pas le statut de sortie approprié dans $?.

$ irb   >> require "open3"    => true   >> stdin, stdout, stderr = Open3.popen3('false')   => [#<IO:0x6f39c0>, #<IO:0x6f3984>, #<IO:0x6f3920>]   >> $?   => #<Process::Status: pid=26285,exited(0)>   >> $?.to_i   => 0

Open4#popen4

Open4 # popen4 est un Ruby Gem créé par Ara Howard. Cela fonctionne de manière similaire à open3 sauf que nous pouvons obtenir le statut de sortie du programme. popen4 renvoie un identifiant de processus pour le sous-shell et nous pouvons obtenir le statut de sortie de l’attente de ce processus. (Vous devrez faire un bundle install open4 pour l’utiliser.)

$ irb   >> require "open4"    => true   >> pid, stdin, stdout, stderr = Open4::popen4 "false"    => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]   >> $?   => nil   >> pid   => 26327   >> ignored, status = Process::waitpid2 pid   => [26327, #<Process::Status: pid=26327,exited(1)>]   >> status.to_i   => 256

Une fonctionnalité intéressante est que vous pouvez appeler popen4 en tant que bloc et il attendra automatiquement le statut de retour.

$ irb   >> require "open4"    
=> true   
>> status = Open4::popen4("false") do |pid, stdin, stdout, stderr|   ?>            puts "PID #{pid}"    >>          end   PID 26598   => #<Process::Status: pid=26598,exited(1)>   >> puts status   256   => nil

Partagez sur: