Pour conserver un enregistrement des scripts utilisateur lancés lors de certaines sessions ou lors d'un certain nombre de sessions, ajoutez les lignes suivantes à chaque script dont vous voulez garder la trace. Ceci va conserver un fichier d'enregistrement des noms de script et des heures d'invocation.
# Ajoute (>>) ce qui suit à la fin de chaque script tracé. date>> $FICHIER_SAUVEGARDE #Date et heure. echo $0>> $FICHIER_SAUVEGARDE #Nom du script. echo>> $FICHIER_SAUVEGARDE #Ligne blanche comme séparateur. # Bien sur, FICHIER_SAUVEGARDE défini et exporté comme variable d'environnement # dans ~/.bashrc (quelque chose comme ~/.scripts-run) |
L'opérateur >> ajoute des lignes dans un fichier. Qu'en est-il si vous voulez ajouter une ligne au début d'un fichier existant, c'est-à-dire la coller au tout début?
fichier=donnees.txt titre="***Ceci est la ligne de titre des fichiers texte de données***" echo $titre | cat - $fichier >$fichier.new # "cat -" concatène stdout dans $file. # Le résultat final est l'écriture d'un nouveau fichier avec $titre ajouté au #+ *début*. |
Bien sûr, sed peut aussi le faire.
Un script shell peut agir comme une commande interne à l'intérieur d'un autre script shell, d'un script Tcl ou d'un script wish, voire même d'un Makefile. Il peut être appelé comme une commande shell externe dans un programme C en utilisant l'appel system(), c'est-à-dire system("nom_du_script");.
Réunissez les fichiers contenant vos définitions et vos fonctions les plus utiles. Quand nécessaire, << incluez >> un ou plus de ces << fichiers bibliothèque >> dans des scripts avec soit le point (.) soit la commande source.
# BIBLIOTHEQUE SCRIPT # ------ ------- # Note: # Pas de "#!" ici. # Pas de code exécuté immédiatement non plus. # Définition de variables ici ROOT_UID=0 # Root a l'identifiant utilisateur ($UID) 0. E_NOTROOT=101 # Pas d'erreur de l'utilisateur root. MAXRETVAL=256 # Code de retour (positif) maximum d'une fonction. SUCCESS=0 FAILURE=-1 # Fonctions Usage () # Message "Usage:". { if [ -z "$1" ] # Pas d'argument passé. then msg=nom_du_fichier else msg=$@ fi echo "Usage: `basename $0` "$msg"" } Verifier_si_root () # Verifier si le script tourne en tant que root. { # A partir de l'exemple "ex39.sh". if [ "$UID" -ne "$ROOT_UID" ] then echo "Doit être root pour lancer ce script." exit $E_NOTROOT fi } Creer_Nom_Fichier_Temporaire () # Crée un nom de fichier temporaire "unique". { # A partir de l'exemple "ex51.sh". prefixe=temp suffixe=`eval date +%s` Tempfilename=$prefixe.$suffixe } est_alpha2 () # Teste si la chaine de caractères *entière* est # alphabétique. { # A partir de l'exemple "isalpha.sh". [ $# -eq 1 ] || return $FAILURE case $1 in *[!a-zA-Z]*|"") return $FAILURE;; *) return $SUCCESS;; esac # Merci, S.C. } abs () # Valeur absolue. { # Attention: Valeur de retour maximum = 256. E_ARGERR=-999999 if [ -z "$1" ] # Il est nécessaire de passer un argument. then return $E_ARGERR # Code d'erreur évident renvoyé. fi if [ "$1" -ge 0 ] # Si non-négatif, then # absval=$1 # reste tel quel, else # Sinon, let "absval = (( 0 - $1 ))" # change son signe. fi return $absval } tolower () # Convertit le(s) chaîne(s) de caractères passées comme { #+ as argument(s) en minuscule. if [ -z "$1" ] # Si aucun argument n'est passé, then #+ envoyez un message d'erreur echo "(null)" #+ (message d'erreur étant un pointeur null style C) return #+ et sort de la fonction. fi echo "$@" | tr A-Z a-z # Transforme tous les arguments passés ($@). return # Utilisez la substituion de commande pour initialiser une variable à la sortie #+ d'une commande. # Par exemple: # anciennevar="Un EnseMBle dE LetTres miNusCuleS Et MaJuscuLeS" # nouvellevar=`tolower "$anciennevar"` # echo "$nouvellevar" # un ensemble de lettre minuscules et majuscules # # Exercice: Réécrire cette fonction pour changer le(s) argument(s) minuscule(s) #+ en majuscules ... toupper() [facile]. } |
Utiliser des entêtes de commentaires pour accroître la clarté et la compréhension des scripts.
## Attention. rm -rf *.zzy ## Les options "-rf" de "rm" sont très dangereux, ##+ spécialement avec des caractères joker. #+ Suite de la ligne. # Ceci est la ligne 1 #+ d'un commentaire multi-ligne. #+ et ceci est la ligne finale. #* Note. #o Elément d'une liste. #> Autre point de vue. while [ "$var1" != "end" ] #> while test "$var1" != "end" |
En utilisant la variable d'état de sortie $?, un script peut tester si un paramètre contient seulement des chiffres, ainsi il peut être traité comme un entier.
#!/bin/bash SUCCESS=0 E_BADINPUT=65 test "$1" -ne 0 -o "$1" -eq 0 2>/dev/null # Un entier est soit égal à 0 soit différent de 0. # 2>/dev/null supprime les messages d'erreur. if [ $? -ne "$SUCCESS" ] then echo "Usage: `basename $0` integer-input" exit $E_BADINPUT fi let "sum = $1 + 25" # Donnera une erreur si $1 n'est pas un entier. echo "Sum = $sum" # Toute variable, pas simplement un paramètre de ligne de commande, peut être #+ testé de cette façon. exit 0 |
L'échelle 0 - 255 des valeurs de retour des fonctions est une limitation importante. Les variables globales et autres moyens de contourner ce problème sont souvent des problèmes en eux-même. Une autre méthode, pour que la fonction communique une valeur de retour au corps principal du script, est que la fonction écrive sur stdout la << valeur de sortie >>, et d'assigner cette sortie à une variable.
Exemple 34-10. Astuce de valeur de retour
#!/bin/bash # multiplication.sh multiplie () # Multiplie les paramètres passés. { # Acceptera un nombre variable d'arguments. local produit=1 until [ -z "$1" ] # Jusqu'à la fin de tous les arguments... do let "produit *= $1" shift done echo $produit # N'affichera pas sur stdout, } #+ car cela va être affecté à une variable. mult1=15383; mult2=25211 val1=`multiplie $mult1 $mult2` echo "$mult1 X $mult2 = $val1" # 387820813 mult1=25; mult2=5; mult3=20 val2=`multiplie $mult1 $mult2 $mult3` echo "$mult1 X $mult2 X $mult3 = $val2" # 2500 mult1=188; mult2=37; mult3=25; mult4=47 val3=`multiplie $mult1 $mult2 $mult3 $mult4` echo "$mult1 X $mult2 X $mult3 X mult4 = $val3" # 8173300 exit 0 |
La même technique fonctionne aussi pour les chaînes de caractères alphanumériques. Ceci signifie qu'une fonction peut << renvoyer >> une valeur non-numérique.
capitaliser_ichar () # Capitaliser le premier caractère { #+ de(s) chaîne(s) de caractères passées. chaine0="$@" # Accepte de multiples arguments. premiercaractere=${chaine0:0:1} # Premier caractère. chaine1=${chaine0:1} # Reste de(s) chaîne(s) de caractères. PremierCaractere=`echo "$premiercaractere" | tr a-z A-Z` # Capitalise le premier caractère. echo "$PremierCaractere$chaine1" # Sortie vers stdout. } nouvellechaine=`capitalize_ichar "chaque phrase doit commencer avec une lettre majuscule."` echo "$nouvellechaine" # Chaque phrase doit commencer avec une lettre majuscule. |
Il est même possible pour une fonction de << renvoyer >> plusieurs valeurs avec cette méthode.
Exemple 34-11. Une astuce permettant de renvoyer plus d'une valeur de retour
#!/bin/bash # sum-product.sh # Une fonction peut "renvoyer" plus d'une valeur. somme_et_produit () # Calcule à la fois la somme et le produit des arguments. { echo $(( $1 + $2 )) $(( $1 * $2 )) # Envoie sur stdout chaque valeur calculée, séparée par un espace. } echo echo "Entrez le premier nombre " read premier echo echo "Entrez le deuxième nombre " read second echo valretour=`somme_et_produit $premier $second` # Affecte à la variable la sortie #+ de la fonction. somme=`echo "$valretour" | awk '{print $1}'` # Affecte le premier champ. produit=`echo "$valretour" | awk '{print $2}'`# Affecte le deuxième champ. echo "$premier + $second = $somme" echo "$premier * $second = $produit" echo exit 0 |
Ensuite dans notre liste d'astuces se trouvent les techniques permettant de passer un tableau à une fonction, << renvoyant >> alors un tableau en retour à la fonction principale du script.
Le passage d'un tableau nécessite de charger des éléments séparés par un espace d'un tableau dans une variable avec la substitution de commandes. Récupérer un tableau comme << valeur de retour >> à partir d'une fonction utilise le stratagème mentionné précédemment de la sortie (echo) du tableau dans la fonction, puis d'invoquer la substitution de commande et l'opérateur ( ... ) pour l'assigner dans un tableau.
Exemple 34-12. Passer et renvoyer un tableau
#!/bin/bash # array-function.sh: Passer un tableau à une fonction et... # "renvoyer" un tableau à partir d'une fonction Passe_Tableau () { local tableau_passe # Variable locale. tableau_passe=( `echo "$1"` ) echo "${tableau_passe[@]}" # Liste tous les éléments du nouveau tableau déclaré #+ et initialisé dans la fonction. } tableau_original=( element1 element2 element3 element4 element5 ) echo echo "tableau_original = ${tableau_original[@]}" # Liste tous les éléments du tableau original. # Voici une astuce qui permet de passer un tableau à une fonction. # ********************************** argument=`echo ${tableau_original[@]}` # ********************************** # Emballer une variable #+ avec tous les éléments du tableau original séparés avec un espace. # # Notez que d'essayer de passer un tableau en lui-même ne fonctionnera pas. # Voici une astuce qui permet de récupérer un tableau comme "valeur de retour". # ***************************************** tableau_renvoye=( `Passe_Tableau "$argument"` ) # ***************************************** # Affecte une sortie de la fonction à une variable de type tableau. echo "tableau_renvoye = ${tableau_renvoye[@]}" echo "=============================================================" # Maintenant, essayez encore d'accèder au tableau en dehors de la #+ fonction. Passe_Tableau "$argument" # La fonction liste elle-même le tableau, mais... #+ accèder au tableau de l'extérieur de la fonction est interdit. echo "Tableau passé (de l'intérieur de la fonction) = ${tableau_passe[@]}" # Valeur NULL comme il s'agit d'une variable locale. echo exit 0 |
Pour un exemple plus élaboré du passage d'un tableau dans les fonctions, voir Exemple A-11.
En utilisant la construction en double parenthèses, il est possible d'utiliser la syntaxe style C pour initialiser et incrémenter des variables ainsi que dans des boucles for et while. Voir Exemple 10-12 et Exemple 10-17.
Une technique de scripts utile est d'envoyer de manière répétée la sortie d'un filtre (par un tuyau) vers le même filtre, mais avec un ensemble différent d'arguments et/ou options. Ceci est spécialement intéressant pour tr et grep.
# De l'exemple "wstrings.sh". wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \ tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '` |
Exemple 34-13. Un peu de fun avec des anagrammes
#!/bin/bash # agram.sh: Jouer avec des anagrammes. # Trouver les anagrammes de... LETTRES=etaoinshrdlu anagram "$LETTRES" | # Trouver tous les anagrammes de cet ensemble de lettres... grep '.......' | # Avec au moins 7 lettres, grep '^is' | # commençant par 'is' grep -v 's$' | # sans les puriels grep -v 'ed$' # Sans verbe au passé ("ed" en anglais) # Utilise l'utilitaire "anagram" #+ qui fait partie du paquetage de liste de mots "yawl" de l'auteur. # http://ibiblio.org/pub/Linux/libs/yawl-0.2.tar.gz exit 0 # Fin du code. bash$ sh agram.sh islander isolate isolead isotheral |
Voir aussi Exemple 28-2, Exemple 12-18, et Exemple A-10.
Utiliser des << documents anonymes >> pour mettre en commentaire des blocs de code, pour ne pas avoir à mettre en commentaire chaque ligne avec un #. Voir Exemple 17-10.
Lancer sur une machine un script dépendant de la présence d'une commande qui peut être absente est dangereux. Utilisez whatis pour éviter des problèmes potentiels avec ceci.
CMD=commande1 # Premier choix. PlanB=commande2 # Option en cas de problème. command_test=$(whatis "$CMD" | grep 'nothing appropriate') # Si 'commande1' n'est pas trouvé sur ce système, 'whatis' renverra #+ "commande1: nothing appropriate." if [[ -z "$command_test" ]] # Vérifie si la commande est présente. then $CMD option1 option2 # Lancez commande1 avec ses options. else # Sinon, $PlanB #+ lancez commande2. fi |
La commande run-parts est utile pour lancer un ensemble de scripts dans l'ordre, particulièrement en combinaison avec cron ou at.
Il serait bien d'être capable d'invoquer les objets X-Windows à partir d'un script shell. Il existe plusieurs paquets qui disent le faire, à savoir Xscript, Xmenu, et widtools. Les deux premiers ne semblent plus maintenus. Heureusement, il est toujours possible d'obtenir widtools ici.
![]() | Le paquet widtools (widget tools, outils pour objets) nécessite que la bibliothèque XForms soit installée. De plus, le Makefile a besoin d'être édité de façon judicieuse avant que le paquet ne soit construit sur un système Linux typique. Finalement, trois des six objets offerts ne fonctionnent pas (en fait, ils génèrent un défaut de segmentation). |
Pour plus d'efficacité des scripts utilisant des widgets, essayez Tk ou wish (des dérivés de Tcl), PerlTk (Perl avec des extensions Tk), tksh (ksh avec des extensions Tk), XForms4Perl (Perl avec des extensions XForms), Gtk-Perl (Perl avec des extensions Gtk), ou PyQt (Python avec des extensions Qt).
Précédent | Sommaire | Suivant |
Optimisations | Niveau supérieur | Problèmes de sécurité |