Fonctions et alias sous bash <author>Pat Eyler <!-- Compléter: Linux Gazette n°53 - Traducteur: <url url="mailto:tanep@bigfoot.com" name="Pierre Tane"> --> <sect>Fonctions et alias sous bash <p> Par <url url="mailto:pate@gnu.org" name="Pat Eyler"> De nombreux tutoriels et introductions à bash parlent de l'utilisation des alias. Malheureusement, la plupart d'entre eux ne traitent pas les fonctions. C'est vraiment dommage car les fonctions offrent de mutiples avantages que n'ont pas les alias. <sect1>Alias <p> Les alias sont de simples substitutions de chaînes. Le shell prend le premier mot d'une commande et le compare à la liste courante des alias. Par ailleurs, si le dernier caractère d'un alias est un espace, il regarde aussi le mot suivant. Par exemple~: <tscreen><code> $ alias 1='echo ' $ alias 2='ceci est un alias' $ 1 2 ceci est un alias $ </code></tscreen> Les alias ne proposent pas le support d'instructions de branchements, d'arguments sur la ligne de commande ou tous les autres trucs qui rendent la ligne de commande si utile. Par ailleurs, les règles gérant l'expansion des alias sont un peu délicates, suffisamment pour que la page de man de bash <tt/bash(1)/ recommande: <em/placez toujours les définitions d'alias sur des lignes isolées, et n'utilisez jamais la commande alias dans les commandes composées/. <sect1>Une introduction aux fonctions <p> Les fonctions sont en fait des scripts qui tournent dans le contexte courant du shell. (Ce court moment de jargon technique veut dire qu'en l'occurrence, un second shell n'est pas démarré pour faire tourner la fonction, celle-ci est executée par le shell courant.) Les fonctions sont des scripts dans le plein sens du terme et possèdent donc la flexibilité et la puissance de ces derniers. Vous pouvez créer des fonctions de différentes manières. Vous pouvez tout simplement la stocker dans un fichier et exécuter le contenu avec la commande <tt/./ (sur la ligne de commande ou dans un script de démarrage). Vous pouvez également entrer la fonction sur la ligne de commande. Une fonction n'est ainsi disponible que dans la session dans laquelle elle a été définie par l'une des deux méthodes ci-dessus (ou alors dans une session héritée d'un shell parent). Pour créer une fonction sur la ligne de commande, il vous faut faire comme suit~: <tscreen><code> $ gla() { > ls -la | grep $1 > } </code></tscreen> C'est une fonction plutôt simple qui pourrait également être implantée sous la forme d'un alias. (Les raisons pour lesquelles il ne vaut mieux pas le faire via un alias seront exposées plus tard.) Écrite comme précédemment, elle affiche une version plus détaillée du contenu du répertoire courant et recherche toutes les occurences du premier argument. Vous pourriez la rendre plus intéressante en utilisant awk pour trouver les fichiers qui dépassent 1024 octets. Cela donnerait: <tscreen><code> $ gla() { > ls -la | grep $1 | awk ' { if ( $5 > 1024 ) print $0 } ' > } </code></tscreen> Vous ne pourriez pas faire cela avec un alias car il ne suffit plus de remplacer <tt/gla/ par <tt>ls -la | grep</tt>. Comme elle est écrite sous forme de fonction, cela ne pose pas de problème d'utiliser <tt/$1/ (pour se référer au premier argument de <em/gla/) n'importe où dans le corps de vos commandes. Pour un exemple un peu plus conséquent (d'accord, bien plus conséquent), supposez que vous travaillez sur deux projets avec deux dépôts CVS différents. Vous voudrez certainement écrire une fonction qui donne les bonnes valeurs aux variables <tt/CVSROOT/ et <tt/CVS_RSH/ ou encore qui efface ces valeurs si un argument indéterminé est donné en argument. Il serait également intéressant que la commande <tt/cvs update/ soit lancée si vous donnez l'argument <tt/update/ à votre fonction. Avec des alias, vous pouvez le faire mais seulement en lançant de mutiples alias sur la ligne de commande. En utilisant des fonctions, vous pouvez créer un fichier texte (appelé par exemple <tt/setcvs.sh/) contenant ce qui suit~: <tscreen><code> setcvs() { export done="no" if [ "$1" = "unset" ] # Nous voulons effacer toutes les variables then echo -n "Vidage des variables en relation avec CVS : " export CVSROOT="" export CVS_RSH="" export done="yes" echo "Terminé" fi if ( pwd | grep projects/reporting > /dev/null && \ [ "$done" != "yes" ] ) # si nous sommes dans l'espace reporting et que cela n'a pas déjà # été fait then echo -n "Mise en place de cvs pour le projet reporting : " export CVSROOT="issdata:/usr/local/cvs/" export CVS_RSH="ssh" export done="yes" echo "Terminé" fi if ( pwd | grep projects/nightly > /dev/null && \ [ "$done" != "yes" ] ) # si nous sommes dans l'espace nightly et que cela n'a pas déjà # été fait then echo -n "Mise en place de cvs pour le projet nightly : " export CVSROOT="/home/cvs/" export done="yes" echo "Terminé" fi if [ "$1" = "update" ] # Nous voulons mettre à jour l arborescence courante vis à vis du # serveur cvs après avoir initialisé les bonnes variables then if [ -z "$CVSROOT" ] # si $CVSROOT est de longueur nulle (elle a été vidée ou n'a # jamais été initialisée), lancer une erreur et ne rien faire then echo "variables cvs non intialisées ... vérifiez le répertoire dans lequel vous vous trouvez et réessayez" elif [ -n "$CVSROOT" ] # si $CVSROOT est définie, essayer de faire la MAJ then echo "MAJ de l'arborescence locale" cvs -q update echo "Terminé" fi fi } </code></tscreen> Vous pouvez alors enregistrer la fonction et l'utiliser de la manière suivante~: <tscreen><code> $ . ~/scripts/setcvs $ cd $ pwd /home/a257455 $ setcvs unset Vidage des variables en relation avec CVS : Terminé $ echo $CVSROOT $ echo $CVS_RSH $ cd projects/reporting/htdocs/ $ setcvs Mise en place de cvs pour le projet reporting : Terminé $ echo $CVSROOT issdata:/usr/local/cvs/ $ echo $CVS_RSH ssh $ cd ../../nightly/ $ setcvs Mise en place de cvs pour le projet nightly : Terminé $ setcvs update Mise en place de cvs pour le projet nightly : Terminé MAJ de l'arborescence locale Terminé $ cd $ setcvs unset Vidage des variables en relation avec CVS : Terminé $ setcvs update variables cvs non intialisées ... vérifiez le répertoire dans lequel vous vous trouvez et réessayez $ </code></tscreen> Les fonctions peuvent faire bien plus que les alias~: la fonction ci-dessus montre l'utilisation de branchements simples, du contrôle d'erreur et de variables. Bien sûr, elle pourrait être améliorée mais elle montre quand même quelques points importants. Un autre aspect est que les fonctions peuvent être réutilisées dans des scripts alors que ce n'est pas le cas pour les alias. Par exemple, compte tenu du fait que la fonction ci-dessus est stockée dans un fichier appelé <tt>~/scripts/setcvs</tt>, vous pouvez écrire un script comme celui-ci~: <tscreen><code> #!/bin/bash # un script d'exemple # d'abord, charger les fonctions . ~/scripts/setcvs # aller dans les répertoires de projet et les mettre à jour via CVS cd ~/projects/reporting/htdocs setcvs update cd - cd ~/projects/nightly setcvs update # retourner d'où l'on vient et vider les variables CVS cd - setcvs unset </code></tscreen> <sect1>Un dernier avertissement <p> Les alias sont de petites choses bien pratiques mais j'espère qu'après cette introduction, vous allez trouver les fonctions au moins aussi intéressantes (et peut-être même plus utiles). Cependant un défaut commun aux alias et aux fonctions tient dans le fait que vous ne devriez pas remplacer une commande standard par un alias ou une fonction. Il est trop facile de causer des dommages en essayant d'exécuter votre alias alors qu'il n'est pas défini. Imaginez la différence entre~: <tscreen><code> $ alias rm='rm -i' $ cd ~/scratch $ rm * # ici l'alias à rm vous protège et vous efface de manière # interactive le contenu du répertoire courant </code></tscreen> et: <tscreen><code> $ su - # cd /tmp # rm * # ici l'alias à rm n'existe plus et vous effacez # tout ce qu'il y a dans /tmp </code></tscreen> Joyeux hacking~! pate <p>Copyright © 2000, <htmlurl url="mailto:pate@gnu.org" name="Pat Eyler">. Paru dans le numéro 53 de la Linux Gazette de Mai 2000. <p>Traduction française de <htmlurl url="mailto:tanep@bigfoot.com" name="Pierre Tane"> </article>