Les commandes fondamentales de Linux/Programmation bash (script)
[modifier] Introduction à la programmation en bash
Lire au préalable « Les commandes fondamentales de Linux ».
Nous n'exposerons pas tous les aspects de la programmation bash. Consulter pour cela le manuel: man bash.
Le shell bash, comme les autres (korn shell, C shell), permet de lancer des exécutables et des commandes internes, d'interconnecter des processus au moyen de pipes...
Lors de traitements répétitifs on peut éviter de saisir de nombreuses fois un groupe de commandes donné. Il suffit pour cela d'en faire un script, qui les rassemble. S'il s'agit d'une commande simple mieux vaut employer un alias. Dans tous les cas une nouvelle commande simple déclenchera l'exécution du script ou de l'alias, donc des traitements souhaités.
Imaginons par exemple que nous souhaitions disposer d'une nouvelle commande nommée "p1" qui produira la liste des processus correspondants à une commande donnée. On souhaite que "p1" soit générique, donc qu'elle puisse chercher n'importe quelle commande. En résumé on souhaite pouvoir saisir "p1 nom_de_commande" au lieu de ps auxw | grep nom_de_commande, donc par exemple "p1 bash" plutôt que, comme décrit ci-devant, ps auxw | grep bash.
Règles communes à tous les scripts bash:
- la première ligne de tout script bash doit invoquer le shell ainsi: #!/bin/bash
- les paramètres passés par l'utilisateur du script lorsqu'il l'invoquera (via une ligne de commande) sont, au sein du script, des variables nommées "$1" pour le premier, "$2" pour le deuxième, "$3" pour le troisième, etc ... "$@" recèle l'ensemble de ces arguments et "$0" le nom de la commande.
Il suffit donc de créer un fichier nommé "p1" qui contiendra:
#!/bin/bash ps auxw | grep $1
Puis de le rendre exécutable: chmod +x p1
Il sera dès lors possible de l'invoquer: ./p1 bash ou p1 grep
Le script suivant montre ce que contient un fichier ".tar.gz" dont le nom lui est communiqué en argument:
#!/bin/bash tar tvzf $1
Il serait plus utile de pouvoir décider de déclencher le désarchivage:
#!/bin/bash tar tvzf $1 echo -n "Voulez vous désarchiver $1? (o/n): " read archi if [ "$archi" = o ] || [ "$archi" = O ] || [ "$archi" = oui ] || [ "$archi" = OUI ] ; then tar xzpf $1 fi
Une commande employée dans un programme, par exemple (ici!) un script, est parfois appelée instruction.
L'instruction echo affiche un message et son option "n" lui interdit de produire un retour chariot en fin de ligne.
L'instruction read attend une réponse de l'utilisateur et la stocke dans la variable dont le nom lui est fourni en argument (ici: archi).
Les crochets ([ ]) encadrent tous types d'expressions.
L'instruction if permet de tester la valeur de la réponse donnée par l'utilisateur.
Voici la construction typique d'une l'instruction if (qui forme une « clause conditionnelle »):
if (condition) then instruction else instruction fi
fi (if lu à l'envers) marque la fin de la clause.
Si vous souhaitez insérer plusieurs conditions:
if (condition) then instruction elif (condition) then instruction else instruction fi
elif est la forme contractée de "else if" (exprimant « sinon, si ... »).
Le script peut proposer un menu offrant de choisir entre une décompression immédiate ou un examen du contenu:
#!/bin/bash PS3='votre choix ?' select choix in "tar tvzf" "tar xvzf" do $choix $1; done
select facilite la création de menus.
"PS3" est une variable stockant un prompt utilisé par select.
"choix" est le nom de la variable qui contiendra un des éléments de la suite qui suit le mot-clé in. Dans notre cas, "choix" contiendra soit la chaîne "tar tvzf" ou la chaîne "tar xvzf".
Dans la construction do... done, nous plaçons les instructions que nous voulons exécuter. Tout ensemble d'instructions ainsi groupées, par exemple (mais pas uniquement) par do... done, est appelé un bloc. Elle sont ici exécutées en boucle, pour sortir utilisez la combinaison de touches Ctrl-c (maintenir la touche "Ctrl" ou "Control" enfoncée et taper sur la touche du caractère 'c').
"$choix" contiendra donc soit "tar tvzf" soit "tar xvzf" et "$1" contiendra l'argument (ici le nom du fichier compressé) fourni lors de l'invocation du script.
Si notre script s'appelle "ctgz", son exécution se déroulera ainsi: ./ctgz nom_de_fichier.tar.gz
1) tar tvzf 2) tar xvzf votre choix ?
L'utilisateur n'a plus qu'à taper "1" ou "2".
Voici une amélioration par ajout de 4 lignes (les premières) visant à s'assurer que l'argument fourni est bien le nom d'un fichier et qu'il est possible de lire ce dernier:
#!/bin/bash if [ ! -r $1 ] ; then echo Je ne peux lire le fichier $1 exit 4 fi PS3='votre choix ?' select choix in "tar tvzf" "tar xvzf" do $choix $1; done
Le point d'exclamation marque la négation, donc la première ligne se lit:
if [ ! -r $1 ] ; then si ( NON de (fonction déterminant si existe en tant que fichier et est lisible) appliquée à l'argument_fourni_par_l'utilisateur ) , alors
for permet de répéter l'exécution d'un bloc. Sa syntaxe est très proche de celle de select:
for nom [in liste] do instructions utilisant $nom done
Exemple: Le script suivant liste le contenu de plusieurs fichiers compressés. La variable "$@" contient les arguments communiqués par l'utilisateur lors de l'invocation du script (en théorie il s'agit de la liste des noms des fichiers):
#!/bin/bash for nomfichier in $@ do echo $nomfichier tar tvzf $nomfichier done
while exécute le bloc tant que la condition reste vraie. until exécute le bloc jusqu'à ce qu'elle le devienne.
Exemple:
#!/bin/bash until tar tvzf $1; do echo "tentative de décompression" read done
Avec cette boucle, tant que le fichier n'aura pas pu être décompressé et désarchivé, tar sera exécuté indéfiniment ... pour en sortir utilisez la combinaison de touches Ctrl-c.