ol>

Scripts de qualitéCette page présentes un ensemble de solutions permettant d'améliorer la qualité des scripts que vous écrivez. Il ne s'agit ni de normes ni de bonnes pratiques mais d'idées.

Organisation d'un script

Il est généralement assez intéressant d'organiser un script de la manière suivante :

  1. Entête - commentaire
  2. Validation des options
  3. Test des arguments
  4. Initialisation des variables
  5. Définition des fonctions
  6. Code principal
#!/bin/ksh

# Ce script permet de donner un exemple d'organisation de script
#
# Options
# -a <num>
# 	Cette option prend un argument numérique (obligatoire)
# -b
# 	Cette option sert uniquement d'exemple (facultative)
#
# Paramètres
# paramètre 1
#	Un nom de fichier qui doit exister

echo $* | grep -q '.*-a.*' || echo -a absent >&2 && exit 1
nombre_option_a=$(echo $* | sed 's/.*-a *([0-9]+).*/\1/')
presence_b=$(echo $* | grep -q '.*-b.*')
fic=$(echo $* | sed 's/(.*)-a *[0-9]+(.*)/\1\2/;s/-b//;s/ +/ /')
[[ ! -e $fic ]] && echo fichier introuvable >&2 && exit 1

# Variable inutile 1
variable1=45
# Variable inutile 2
var2=78

# Cette fonction est vide, elle ne sert qu'à donner un exemple de
# définition de fonction dans le script
function afficher_truc {
	echo truc
}

affichier_truc
cat $fic
exit 0
Erreurs fréquentes

L'utilisation maladroite de cat

La commande cat sert en réalité on concaténer des fichiers. Son utilisation avec un seul fichier est une perte de temp et coute un processus

Utiliser cat dans une invite de commande ksh pour visualiser le fichier est la seule utilisation de cette commande avec un unique fichier en argument qui soit justifiée. La mauvaise utilisation de cette commande a un impact sur la vitesse d'exécution des scripts si elle est utilisée de cette manière :

cat fichier | awk...

Dans ce cas là, le fichier est lu puis affiché dans la sortie standard qui est en réalité un fichier spécial. Ce fichier spécial est ensuite utilisé comme entrée standard de la commande awk. Pour se passer de l'étape intermédiaire de création de fichier spécial, on peut tout simplement rediriger l'entrée standard de awk sur le fichier de la manière suivante :

awk ... < fichier
time cat fichier | awk '{print $1;}' > /dev/null
	 0.07s real	 0.00s user	 0.09s system
time awk '{print $1;}' < fichier > /dev/null
	 0.04s real	 0.00s user	 0.03s system

L'utilisation maladroite de echo

La mauvaise utilisation de cette commande est la suivante :

variable="quelque chose ou le résultat d'une commande"
commande -options $(echo $variable)

En fonction de ce qui est contenu dans la variable, la commande exacte est généralement la suivante :

variable="quelque chose ou le résultat d'une commande"
commande -options $variable

Et sauf exception, l'utilisation de la commande écho entre backquotes ou entre $() n'a aucun sens. Sauf dans le cas ou une variable contient elle-même un nom de variable que l'on souhaite interpréter.

L'utilisation maladroite des paramètres

Une particularité du shell POSIX est que l'interprétation des blancs se fait après l'expansion des noms de variables. Par exemple, si on écrit

x='un nom de fichier avec espaces.txt'
ls $x

alors $x sera expansé en un nom de fichier avec espaces.txt, et la commande exécutée sera ls un nom de fichier avec espaces.txt. À moins d'avoir une bonne raison, toujours utiliser la syntaxe "$x" pour utiliser une variable shell.

L'utilisation maladroite de ls *

La mauvaise utilisation de la commande ls est la suivante :

for f in $(ls *)
do
	commande "$f"
done

Bien sur, ce script fonctionne mais il créé un processus supplémentaire (ls). L'expansion du * est réalisée par le shell sans avoir besoin de la commande ls.

for f in *
do
	commande "$f"
done

Attention, une erreur similaire est souvent commise avec echo *. Il est parfois possible que la commande sache utiliser plusieurs arguments (comme rm) dans ce cas, il vaut mieux utiliser directement :

rm -f *

L'utilisation maladroite de redirections

Il n'est pas rare de voir de nombreux pipes qui pourraient soit être évités par l'utilisation d'options des commandes soit qui pourraient être regroupés dans une seule commande.

commande | grep '..*' | wc -l

peut être remplacé par :

commande | grep -c '..*'

Ou généralement, tous les pipes qui enchainent plusieurs awk de suite ou plusieurs sed de suite peuvent être groupés. Et il est toujours possible d'éviter d'enchainer un awk et un sed. Il est presque également toujours possible d'éviter l'enchainement d'un grep et d'un awk de la manière suivante :

ps -l | grep -v 'STATE' | awk '{print $2}'

peut être remplacé par

ps -l | awk '!/STATE/{print $2}'