af83

Découvrons le module Shellwords pour Ruby

La bibliothèque standard de Ruby comporte pas mal de modules vieillissants, dont le code aurait plus sa place dans des gems à part. Mais on peut aussi y trouver quelques perles. Je vous ai déjà parlé des Set et des Struct. Aujourd'hui, je vais compléter cette liste, en y ajoutant Shellwords.

La description de Shellwords dit :

This module manipulates strings according to the word parsing rules of the UNIX Bourne shell.

Ce que l'on pourrait traduire en français par :

Ce module manipules des chaînes de caractères en respectant les règles des shells Bourne UNIX pour découper les mots.

La première utilisation de ce module est de pouvoir construire des lignes de commande pour le shell. Par exemple, si on veut compter le nombre de lignes d'un fichier, on peut faire :

filename = "/path/to/my/file"
nb_lines = `wc -l < #{filename}`.to_i

Mais, si pour une raison ou une autre, le nom de fichier comporte une espace, cela ne va plus marcher. Dans la ligne de commande, l'espace se comportera comme un séparateur de mots et le shell va chercher deux fichiers au lieu d'un. Pour corriger le problème, on peut faire appel à Shellwords de cette façon :

require "shellwords"

filename = "/path/to/my/file"
nb_lines = `wc -l < #{Shellwords.escape(filename)}`.to_i

Note : l'espace n'est pas le seul caractère à poser problème dans les lignes de commande du shell. On peut également citer les retours à la ligne, les guillemets, l'anti-slash, le point-virgule (qui sert à séparer des instructions) ou encore le dollar (pour référencer des variables).

Si vous avez un tableau, il existe également une petite méthode utilitaire pour vous aidez, Shellwords.join. Voici un exemple :

require "shellwords"

pattern = "foo bar"
files = %w(some files)
open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe|
  # ...
}

Cette méthode applique Shellwords.escape sur chaque élément du tableau, puis fais un join(' ') pour construire cette partie de la ligne de commande finale.

On a vu comment construire une ligne de commande à partir de mots, mais la réciproque est également valable : Shellwords peut aussi nous aider à découper en mots une ligne de commande. Exemple :

require "shellwords"

argv = Shellwords.split('here are "two words"')
argv #=> ["here", "are", "two words"]

Cette méthode peut s'avérer bien pratique, même en dehors du contexte du shell. Imaginer que vous ayez un système qui permette de saisir des tags séparés par des espaces :

tags = gets.split(' ')

Si l'utilisateur saisit la ligne Ruby Shell Tips, tags sera le tableau avec les 3 tags : ["Ruby", "Shell", "Tips"]. Puis, un utilisateur vous remonte son besoin de saisir des tags avec des espaces dedans, comme Open Source ou Free Software. Vous ne voulez pas changer le séparateur, juste avoir un moyen d'indiquer si l'espace fait parti du tag ou non. Le shell a déjà résolu ce problème pour vous. Il propose deux façons de saisir un mot avec des espaces : soit le mettre entre des guillemets, soit utiliser le caractère d'échappement \. Et avec Shellwords, c'est très facile de proposer le même mécanisme :

require "shellwords"
tags = Shellwords.split(gets)

Et maintenant, si l'utilisateur saisit la ligne "Free Software" Open\ Source, nous obtenons bien un tableau avec deux tags : ["Free Software", "Open Source"]. Ne trouvez-vous pas que c'est une utilisation bien pratique de Shellwords ?

blog comments powered by Disqus