Gérer correctement les options de vos commandes

Les langages de script shell sous Unix sont des langages puissants. Ils proposent tellement de facilités qu’au final, si on ne fait pas attention, ces facilités se retournent contre vous.

Voici quelques règles et astuces pour vous éviter quelques nuits blanches à chercher pourquoi un script qui marchait parfaitement se met tout à coup à déconner.

Option ou paramètre

Du point de vue d’Unix, une commande n’est rien d’autre qu’une liste d’arguments dont le premier représente l’exécutable. Les arguments ne sont que des chaînes de caractères.

Dans ce cas, comment reconnaître une option (qui définira le comportement de la commande) d’un paramètre (un nom de fichier, de répertoire etc.) ?

La distinction passe par une convention. Et il en existe plusieurs !

Les substitutions du shell

Sous Unix, les langages de script shell opèrent des substitutions sur les commandes que vous tapez avant de les exécuter :

Ce sont ces substitutions qui créent des failles. Et on peut même les combiner !

La protection des variables

Veillez à toujours protéger vos variables en les entourant avec des doubles quotes (") car le moindre espace qu’elles pourraient contenir aurait des conséquences néfastes.

Donc commande $fichier est à proscrire. Il faut préferer commande "$fichier".

La désactivation de l’interprétation des options

La substitution des variables n’est pas la seule chose à prendre en compte. Il faut également se méfier des variables quand la commande à exécuter supporte une grande variété d’options.

Par exemple, si la commande que vous exécutez est touch "$fichier", cette dernière générera une erreur si la variable $fichier contient la chaîne -f (La commande touch indiquera opérande fichier manquant sous Linux).

C’est tout à fait normal puisque, pour cette commande, vous n’avez fourni que l’option -f, sans aucun fichier.

Pour remédier à cela, la plupart des commandes permettent de spécifier les options au début et de les séparer par un double tiret -- des paramètres.

Pour être la plus fiable possible, la commande aurait dû être écrite touch -- "$fichier"

printf vs echo

La commande echo est probablement la commande la plus utilisée dans les scripts shells. Elle pose néanmoins plusieurs problèmes.

Premièrement elle n’est pas standardisée. En fonction de votre OS ou du shell utilisé (Bash, CSH, KSH etc.), cette commande n’accepte pas les mêmes paramètres ni n’interprète les séquences d’échappement de la même façon.

Deuxièmement il n’est souvent pas possible de désactiver l’interprètation des options en utilisant le double tiret -- ce qui empêche l’affichage de certaines chaînes de caractères. Par exemple sous Bash, il n’est pas possible d’afficher les chaînes -e et -E car elles sont interprêtées comme des options.

La solution qui corrige ces problèmes consiste à utiliser la commande printf. Sous Bash, cela n’a pas d’impact sur les performances car elle fait partie des commandes internes.

Pour émuler la commande echo "$variable", il faut utiliser printf '%s\n' "$variable". Sous cette forme, la chaîne contenue dans la variable $variable sera affichée telle qu’elle, quels que soient les caractères qu’elle pourrait contenir.

Je ne saurais donc trop vous recommander de remplacer ce pattern vu régulièrement : echo "$variable" | commande par printf '%s' "$variable" | commande.

Récapitulatif

En résumé :