Les scripts bash

De UnixManiax
Aller à la navigation Aller à la recherche


Notre premier script

Bash n'est pas qu'un simple interpréteur de commandes. Il permet d'effectuer une suite de commandes rassemblées dans un fichier exécutable, appelé "script". A ce titre, bash est un véritable langage de programmation.

Comme tout bon programmeur, nous allons commencer par un "helloworld". Il s'agira simplement d'afficher le texte "hello world !" à l'écran.

Pour préciser à linux que l'interpréteur de commandes utilisé est bash (utile si ce n'est pas le shell par défaut), tout script va commencer par la ligne #!/bin/bash.

Pour insérer un commentaire, mettez un # au début de la ligne. Chaque instruction se trouvera sur un ligne.

Et voilà, c'est tout ce que nous avons besoin de connaitre pour écrire un simple script. Maintenant, ouvrer votre éditeur de texte préféré et tapez les lignes ci-dessous. Puis sauvegardez le tout sous le nom helloworld.sh.

#!/bin/bash 			
# premier script bash 			
echo "hello world !"

Comme notre script vient d'être créé, il faut préciser au système que c'est un fichier exécutable en tapant chmod +x helloworld.sh. C'est fait une fois pour toutes, et il n'est heureusement pas nécessaire de recommencer à chaque modification du script.

Maintenant exécutons notre script en faisant précéder le nom de "./". Le "./" sert à indiquer que le script se trouve dans le répertoire courant. C'est indispensable si le répertoire courant n'est pas inclu dans la variable PATH (plus dinfos sur PATH ici).

chmod +x helloworld.sh 			
$ ./helloworld.sh 			
hello world ! 			
$

Et voilà, c'est pas plus compliqué que ça ! Bien sûr, ce premier script n'est pas d'une utilité foudroyante. Mais si vous devez taper régulièrement une même suite d'instructions, alors il peut être pratique de les rassembler dans un script. Par exemple, pour configurer votre firewall, plutôt que de taper toutes les commandes iptables bien complexes à chaque connexion, vous n'avez qu'à faire un script que vous lancez automatiquement à chaque démarrage.

Les variables

Les variables peuvent contenir n'importe quelle valeur. On ne déclare pas le type de la variable, contraitement à beaucoup de langages. Ici, il est déterminé automatiquement : nombre entier ou chaines de caractère.

On les déclare en mettant leur nom suivi du signe '=' et de la valeur, sans espaces. Si la valeur est une suite de caractès sééparés par des espaces, il faudra alors mettre des guillemets ou des apostrophes. Pour utiliser les variables, on met leur nom précédé du signe '$' sans espace.

exemple :

#!/bin/bash
nb=25
mon_texte="bonjour tout le monde"
echo $nb
echo $mon_texte

A l'écran ça nous donne :

$ ./test.sh
25
bonjour tout le monde
$

Voici maintenant un exemple de manipulation des variables, où on voit qu'on ne peut pas faire n'importe quoi avec les variables.

#!/bin/bash
nb=25
mon_texte="bonjour tout le monde"
mon_texte_2="coucou"
echo $nb
echo $mon_texte
echo $mon_texte_2
let $[ nb=$nb+1 ]
let $[ mon_texte=$mon_texte+1 ]           # erreur faite exprès !!
mon_texte_2=$mon_texte_2" les gens"
echo "nb + 1 = $nb"
echo "mon_texte + 1 = $mon_texte"
echo $mon_texte_2

Et le résultat :

$ ./test.sh
25
bonjour tout le monde
coucou
./test.sh: mon_texte=bonjour tout le monde+1 : syntax error in expression (error token is "tout le monde+1 ")
nb + 1 = 26
mon_texte + 1 = 0
coucou les gens

On contate bien qu'on ne peut pas faire d'opération arithmétique avec des chaines de caractères, ce qui est normal, évidement. Dans un langage compilé avec déclaration du type de variable, comme le C, ont aurait été averti dès la compilation. Ici, il faut bien faire attention à ce qu'on fait. C'est la contrepartie de la souplesse apportée par bash.

Quelques variables utiles

  • $$ : affiche le numéro de processus (pid) du shell
  • $! : affiche le pid de la dernière commande lancée en tâche de fond (avec &)
  • $? : affiche la valeur retrounée par la dernière commande
  • $ : affiche la liste des options avec lesquelles le shell a été appelé

Les commandes composées (; | & || && $() {} ``)

Les commandes qu'on a tapé jusque-là sont des commandes simples : une seule commande par ligne, les unes à la suite des autres. Bash permet de faire des commandes composées, c'est à dire plusieurs commandes sur la même lignes, qui vont influer les unes sur les autres.

les commandes séquentielles

Elles s'exécutent l'une après l'autre, exactement comme si on les avait mises sur deux lignes différentes. Le seul intérêt est d'avoir un code plus clair dans certains cas. On sépare simplement les commandes par un point-virgule.

commande1 ; commande2

les commandes redirigées

Le résultat de la commande1 est renvoyé à la commande2.

syntaxe :

commande1 | commande2

exemple :

ps -aux | grep x

Dans l'exemple, on va afficher tous les processus qui contiennent le caractère 'x'.

les commandes en parallèle

On exécute les deux commande1 et commande2 en parallèle. Commande1 est exécutée en tâche de fond.

commande1 & commande2

les commandes "OU exclusif"

Commande2 est exécutée SI et seulement SI commande1 a échoué.

commande1 || commande2

les commandes "ET exclusif"

Commande2 est exécutée SI et seulement SI commande1 a réussi.

commande1 && commande2

les commandes passées en paramètre

Commande2 sert de paramètre à commande1

syntaxe :

commande1 $(commande2) OU commande1 `commande2`

Le caractère ` s'obtient en faisant 'Alt-Gr + 7'. C'est l'apostrophe à l'envers.

exemple : on affiche l'heure

#!/bin/bash 			
heure=$(date +%T) 			
echo $heure

Les trois syntaxes suivantes donnent le même résultat :

#!/bin/bash 			
heure=`date +%T` 			
echo $heure
#!/bin/bash 			
echo $(date +%T)
#!/bin/bash 			
echo `date +%T`

les séries de commandes

On regroupe des commandes entre parenthèses ou accolades. Contrairement aux accolades, les instructions entre parenthèses se déroulent dans un shell secondaire, indépendant du shell actuel. L'utilisation des accolades est donc plutôt conseillée. Avec les accolades, la dernière commande doit se terminer avec un point-virgule.

{ commande1 ; commande2; } OU ( commande1; commande2 )

exemple : on affiche la date et la liste des fichiers, et on envoi le tout vers l'imprimante, plutôt que vers l'écran.

{ date; ls -l; } | lpr

Ecriture à l'écran / lecture au clavier (echo / read)

Ecriture à l'écran

L'écriture à l'écran est très simple, et on l'a déjà vue dans notre premier script. On utilise la commande 'echo' suivie du texte à afficher.

Le texte à afficher peut être entouré de guillemets (") ou de côtes ('), mais ça n'est pas obligatoire. ATTENTION : si on utilise les côtes, les variables (appelées avec $, voir partie 2 - les variables) ne seront pas remplacées par leur valeur ; $variable sera considéré comme un texte (voir exemple ci-dessous).

#!/bin/bash
nom=fred
echo 1. Mon nom est $nom.
echo "2. Mon nom est $nom."
echo '3. Mon nom est $nom.'
echo -n "On ne retourne pas a la ligne."

Et voilà ce que ça nous donne :

$ ./test.sh
1. Mon nom est fred.
2. Mon nom est fred.
3. Mon nom est $nom.        <== la variable $nom n'est pas remplacée par sa valeur !
On ne retourne pas a la ligne.$

Dans l'exemple, on voit aussi une option pratique de echo, qui est l'option -n. Ca permet de ne pas revenir à la ligne à la fin. Dans l'exemple ça ne sert à rien, mais ça va nous servir tout de suite. Si vous voulez connaitre toutes les options de echo, tapez "man echo" dans votre console.

Lecture au clavier

La lecture au clavier se fait avec la commande 'read'. La syntaxe est "read valeur" ou "read val1 val2 val3". Si on rentre une seule valeur, elle sera stockée dans la première variable. Si on rentre plusieurs valeurs, séparées par des espaces, alors la première valeur ira dans la première variable, la deuxième valeur dans la deuxième variable, et ainsi de suite. S'il y a plus de valeurs que de variables, la dernière variable contient toutes les dernières valeur. S'il y a plus de variables que de valeurs, les dernières variables seront vides. Si on ne précise aucun nom de variable, la variable par défaut est "REPLY".

Tout ça sera peut-être plus clair avec l'exemple qui suit. Voici le programme :

#!/bin/bash
echo -n "entrez ce que vous voulez : "
read val1 val2 val3
echo val1=$val1
echo val2=$val2
echo val3=$val3

Et voilà les différants résultats obtenus, en fonction du nombre de valeurs qu'on lui donne :

$ ./test.sh
entrez ce que vous voulez : a b c
val1=a
val2=b
val3=c

$ ./test.sh
entrez ce qe vous voulez : a b c d e
val1=a
val2=b
val3=c d e

$ ./test.sh
entrez ce que vous voulez : a b
val1=a
val2=b
val3=

Le passage de paramètres

Lorsqu'on lance un script, plutôt que de demander les paramètres après avec la commande read, on peut aussi les rentrer dès le lancement du script. On appelle ça le passage de paramètres. La syntaxe est la suivante :

./script param1 param2 param3

On a alors plein de variables qui nous permettent de récupérer chaque paramètre, ainsi que leur nombre.

  • $# : nombre de paramètres
  • $* : affiche l'ensemble des paramètres
  • $@ : affiche l'ensemble des paramètres comme $*. La différence est que $* correspond à une seule valeur, alors que $@ correspond à autant de valeurs qu'il y a de paramètres
  • $0 : affiche le nom du script
  • $1, $2, ..., $9, ${10}, ... : correspondent aux paramètres n°1, 2, etc. Pour les paramètres à plusieurs chiffres, il faut mettre les chiffres entre crochets.

Aller, on va se faire un petit exemple pour voir si vous avez bien compris :

#!/bin/bash
echo "nom du script=$0"
echo "nombre de parametres : $#"
echo '$*'=$*
echo '$@'=$@
echo "param1=$1"
echo "param2=$2"
echo "param3=$3"
echo "param4=$4"

Ce qui nous donne à l'écran :

$ ./test.sh a b c 123
nom du script=./test.sh
nombre de parametres : 4
$*=a b c 123
$@=a b c 123
param1=a
param2=b
param3=c
param4=123


la commande shift

La commande 'shift n' supprime les 'n' premiers paramètres de la liste, et décale la valeur des paramètres. Ainsi, la commande 'shift 3' supprime les trois premiers paramètres. Donc param4 devient param1, param5 devient param2, etc. De plus, la variable $# est diminuée de 'n'.

Rien ne vaut un exemple pour y voir plus clair :

#!/bin/bash
echo "nombre de parametres : $#"
echo "param1=$1"
echo "param2=$2"
echo "param3=$3"
echo "param4=$4"
echo "param5=$5"
shift 3
echo "apres 'shift 3' il nous reste $# parametres"
echo "param1=$1"
echo "param2=$2"
echo "param3=$3"
echo "param4=$4"
echo "param5=$5"

Ce qui nous donne, à l'exécution :

$ ./test.sh a b c d e
nombre de parametres : 5
param1=a
param2=b
param3=c
param4=d
param5=e
apres 'shift 3' il nous reste 2 parametres
param1=d
param2=e
param3=
param4=
param5=


Les structures conditionnelles (if then else while until)

généralités

Une structure conditionnelle est une structure dans laquelle on effectue un test. Le script se comportera de façon différente en fonction du résultat du test. On peut aussi réaliser des boucles tant que le test est vrai.

Les tests peuvent porter sur des fichiers (et/ou répertoires), sur des entiers et sur des chaines de caractères. Leur syntaxe n'est pas la même dans tous les cas. On peut aussi faire des combinaisons de tests.

Il existe deux façons de faire les tests : soit entre crochets, soit avec la commande 'test'.

SI [ tests ] ALORS ... 			
SI test tests ALORS ...

Attention à ne pas oublier l'espace après le premier crochet, et avant le dernier !

Tests sur les fichiers/répertoires

Voici une liste des tests possibles sur les fichiers et/ou répertoires :

  • "-e fichier" : vrai si le fichier/répertoire existe.
  • "-s fichier" : vrai si le fichier à une taille supérieure à 0.
  • "-r fichier" : vrai si le fichier/répertoire est accessible en lecture.
  • "-w fichier" : vrai si le fichier/répertoire est accessible en écriture.
  • "-x fichier" : vrai si le fichier est exécutable ou si le répertoire est accessible.
  • "-O fichier" : vrai si le fichier/répertoire appartient à l'utilisateur.
  • "-G fichier" : vrai si le fichier/répertoire appartient au groupe de l'utilisateur.
  • "-b nom" : vrai si nom représente un périphérique (pseudo-fichier) de type bloc (disques et partitions de disques généralement).
  • "-c nom" : vrai si nom représente un périphérique (pseudo-fichier) de type caractère (terminaux, modems et port parallèles par exemple).
  • "-d nom" : vrai si nom représente un répertoire.
  • "-f nom" : vrai si nom représente un fichier.
  • "-L nom" : vrai si nom représente un lien symbolique.
  • "-p nom" : vrai si nom représente un tube nommé.
  • "fichier1 -nt fichier2" : vrai si les deux fichiers existent et si fichier1 est plus récent que fichier2.
  • "fichier1 -ot fichier2" : vrai si les deux fichiers existent et si fichier1 est plus ancien que fichier2.
  • "fichier1 -ef fichier2" : vrai si les deux fichiers représentent un seul et même fichier.

Tests sur les entiers

  • "entier1 -eq entier2" : vrai si entier1 est égal à entier2.
  • "entier1 -ge entier2" : vrai si entier1 est supérieur ou égal à entier2.
  • "entier1 -gt entier2" : vrai si entier1 est strictement supérieur à entier2.
  • "entier1 -le entier2" : vrai si entier1 est inférieur ou égal à entier2.
  • "entier1 -lt entier2" : vrai si entier1 est strictement inférieur à entier2.
  • "entier1 -ne entier2" : vrai si entier1 est différent de entier2.

Tests sur les chaines de caractères

Les chaines doivent être entourées par des guillemets.

  • "-n "chaîne"" : vrai si la chaîne n'est pas vide.
  • "-z "chaîne"" : vrai si la chaîne est vide.
  • ""chaine1" = "chaine2"" : vrai si les deux chaînes sont identiques.
  • ""chaine1" != "chaine2"" : vrai si les deux chaînes sont différentes.

Les combinaisons de tests

Les combinaisons de tests sont utilisées quand on doit faire plusieurs tests simultanément, c'est à dire, quand on doit répondre à plusieurs conditions.

On utilise les opérateurs && et || comme dans les commandes composées. L'opérateur ! sert à inverser la condition.

  • SI test ALORS commandes FIN : exécute les commandes si test est VRAI
  • SI ! test ALORS commandes FIN : exécute les commandes si test est FAUX
  • SI test1 && test2 ALORS commandes FIN : exécute les commandes si test1 ET test2 sont vrais tous les deux
  • SI test1 -a test2 ALORS commandes FIN : pareil de précédemment, avec une autre notation
  • SI test1 && ! test2 ALORS commandes FIN : exécute les commandes si test1 est VRAI ET test2 est FAUX
  • SI test1 || test2 ALORS commandes FIN : exécute les commandes si test1 OU test2 sont VRAIS
  • SI test1 -o test2 ALORS commandes FIN : pareil de précédemment, avec une autre notation
  • SI ! { test1 || test2 } ALORS commandes FIN : exécute les commandes si NI test1 NI test2 sont VRAIS

Un exemple avec OU :

if [ "$var" == "toto" ] || [ "$var" == "titi" ]
then
  echo "ok"
fi

structure SI ... ALORS

La syntaxe de cette structure est :

if test; then action-1 action-2 ... action-n; fi

Il faut bien mettre un point-virgule après le test et aprè la dernière action. On termine la structure avec la commande fi.

structure SI ... ALORS ... SINON

La syntaxe est :

if test; then action1; else action2; fi

Si le test est vrai, on exécute l'action1 (ou le groupe d'actions1), sinon, on exécute l'action2 (ou le groupe d'actions2). Bien mettre le point virgule après le test et chaque commande ou groupe de commandes.

structure SI ... ALORS ... SINON SI ... ALORS ... SINON

syntaxe :

if test1; then action1; elif test2; then action2; else action3; fi

Si test1 est vrai, on exécute l'action1, sinon, si test2 est vrai, on exécute l'action2, sinon, on exécute l'action3. Bien mettre le point virgule après chaque test et chaque commande ou groupe de commandes.

On peut avoir autant de 'elif' qu'on veut. Voyons un exemple d'utilisation de cette structure :

#!/bin/bash
echo -n "Entrez un nombre entier : " ; read nombre
if [ $nombre -lt 0 ]; then
    echo "$nombre est negatif";
elif [ $nombre -gt 0 ]; then
    echo "$nombre est positif";
else
    echo "$nombre est egal a zero";
fi

Et voilà le résultat :

$ ./test.sh
Entrez un nombre entier : 12
12 est positif

$ ./test.sh
Entrez un nombre entier : -5
-5 est negatif

$ ./test.sh
Entrez un nombre entier : 0
0 est egal a zero


structure TANT QUE ... FAIRE

Il existe deux commandes pour faire ça : while et until. While va répéter la boucle tant que le test est vrai. Until va répéter la boucle jusqu'à ce que le test soit vrai.

La syntaxe des deux commandes est :

while test; do action1 action2; done 			
until test; do action1 action2; done

Comme avec les structures précédentes, on met un point-virgule après le test et après le groupe d'actions.

Il arrive très souvant, en programmation, qu'on veuille répéter une opération un certain nombre de fois. Dans ce cas, on utilise un entier qui va nous servir de compteur. Pour incrémenter ce compteur, on utilise la commande let suivie de l'opération à effectuer, selon la syntaxe suivante :

let $[ commande ]

Voici un exemple très simple, qui affiche les nombres de 1 à 10.

#!/bin/bash
i=1 # on initialise le compteur
while [ $i -le 10 ]; do
    echo $i
    let $[ i+=1 ] # incremente i de 1 a chaque boucle
done

Et on obtient :

./test.sh
1
2
3
4
5
6
7
8
9
10

L'instruction "i+=1" sert à incrémenter i de 1. C'est une syntaxe employée dans de nombreux langage, mais qui n'est peut-être pas claire pour le débutant. On peut la remplacer par "i=$i+1", ce qui nous donne "let $[ i=$i+1 ]". Celle-ci est plus facilement compréhensible.


Les autres structures (for in do case select)

structure POUR chaque élément de la liste FAIRE ...

Cette structure nous permet de faire une action pour chaque élément d'une liste. La liste peut être donnée directement, ou être le résultat d'une commande.

Syntaxe :

for element in liste_des_elements; do actions; done

On met un point-virgule après la liste des éléments et après le groupe d'actions.


Exemple 1, où on tape la liste manuellement :

#!/bin/bash
for mois in janvier fevrier mars avril; do
    echo $mois;
done

Le résultat est :

./test.sh
janvier
fevrier
mars
avril


Exemple 2, où la liste est le résultat d'une commande. Au lieu de faire un exemple bête comme j'en ai l'habitude... Si, si... On va faire un script très pratique, qui permet de renomer des fichiers par lot. On appelle le script avec deux paramètres : le premier est l'extention actuelle des fichiers, le second est l'extention qu'on veut donner. Et comme maintenant vous êtes très forts, on va même vérifier que le nombre de paramètres est bon. C'est plus prudent avec les étourdis !

#!/bin/bash
if ! [ $# -eq 2 ]; then
    echo "Le nombre de parametres doit etre de 2 (ancienne-extension nouvelle-extention) !"
else
    ext1=$1
    ext2=$2
    for file in `ls *.$ext1`; do
    mv $file ${file%.$ext1}.$ext2;
    done
fi

Voilà le résultat :

$ ls
a.txt  b.txt  c.txt  renome.sh
$ ./renome.sh
Le nombre de parametres doit etre de 2 (ancienne-extension nouvelle-extention) !
$ ./renome.sh txt tmp
$ ls
a.tmp  b.tmp  c.tmp  renome.sh

Et voilà le travail ! Tous nos fichiers .txt ont été renomés en .tmp. Et nous avons été avertis quand le nombre de paramètres n'était pas bon.

structure DANS chacun des cas suivants FAIRE ...

Pour ce type de structure, on utilise la commande case. Cette commande est équivalente à une série de if ... elif ... elif ... elif ... else ... fi, mais ç apparait de façon beaucoup plus claire et lisible.

Syntaxe :

case valeur in
    cas_1) action_1;;
    cas_2) action_2;;
    cas_3) action_3;;
    *) action_sinon;;
esac

Pour chaque possibilité, on a une action associée. Si aucun des cas n'est rencontré, c'est l'action par défaut (correspondant à "*)") qui est exécutée.

Chaque action ou suite d'actions se termine par un double point-virgule. La structure se termine par "esac" ("case" écrit à l'envers).

La commande select

Syntaxe :

select valeur in liste_de_valeurs; do actions; done

La commande select affiche un menu qui vous propose le choix parmis la liste définie. Chaque ligne est numérotée en partant de 1. Select affiche une phrase qui vous demande d'entrer votre choix. Cette phrase est contenu dans la variable PS3 qu'il faudra initialiser avant (par défaut, elle contient "#?"). Une fois que vous avez validé votre réponse, elle est mémorisée dans la variable REPLY.

Select repose indéfiniment la même question, jusqu'à ce qu'on quitte le script avec les touches ctrl-c. Pour éviter ça, on utilise la commande "break" qui permet de sortir de la structure pour passer à la suite du script. Il est fortement conseillé d'utiliser select en combinaison avec case. Ainsi, on peut facilement orienter le déroulement du script en fonction de la valeur choisie.

Comme tout ça n'est pas vraiment simple dit comme ça, on va faire un exemple pour montrer que finalement ça n'est pas si complexe que ça en a l'air. Au contraire, on peut faire très facilement un menu.

#!/bin/bash
PS3="> selectionnez un plat : " # definie l'invite du menu
echo " -- menu du jour -- " # affiche un titre
select choix in cassoulet pizza "salade du chef" "quitter (q|Q)"; do
case $REPLY in
    1) echo "Voici votre $choix."
       echo "Desirez-vous autre chose ?";;
    2) echo "Une pizza ? Excellent choix !"
       echo "Desirez-vous autre chose ?";;
    3) echo "Et une $choix, une !"
       echo "Desirez-vous autre chose ?";;
    4|Q*|q*) echo "Au revoir" # on quitte en appuyant sur 4, ou en tapant un mot commancant par Q ou q
       break;;
    *) echo "Je n'ai pas compris votre commande. Veuillez repeter svp.";;
esac
done

Voilà ce que ça donne à l'écran :

$ ./test.sh
 -- menu du jour --
1) cassoulet
2) pizza
3) salade du chef
4) quitter (q|Q)
> selectionnez un plat : azerty
Je n'ai pas compris votre commande. Veuillez repeter svp.
1) cassoulet
2) pizza
3) salade du chef
4) quitter (q|Q)
> selectionnez un plat : 2
Une pizza ? Excellent choix !
Desirez-vous autre chose ?
1) cassoulet
2) pizza
3) salade du chef
4) quitter (q|Q)
> selectionnez un plat : q
Au revoir

Et voilà comment qu'on est trop forts !

Les fonctions

Pour simplifier et rendre plus lisible les scripts, bash permet l'utilisation de fonctions. Une fonction est un sous-programme qui peut être appelé n'importe quand, et aussi souvant que nécéssaire. On peut lui envoyer des variables, et elle peut nous retourner un résultat. A l'intérieur d'une fonction, on peut créer une variable locale (qui n'existe qu'à l'intérieur de la fonction) avec le mot clé "local".

On accède aux paramètres de la fonction de la même façon que dans un script, avec les variables $#, $*, $@, $1, $2, etc. Seul $0 ne change pas (pour rappel, $0 affiche le nom du script).

Pour renvoyer un valeur au programme principal, c'est le mot clé "return" qui est utilisé. Sinon, c'est le résultat de la dernière commande exécutée qui est renvoyé.

Une fonction peut s'appeler elle-même. On dit qu'elle est récursive.

Attention : il faut utiliser la commande "exit" avec prudence, car elle ne termine pas seulement la fonction, mais aussi le script !

Pour déclarer une fonction, soit on met un nom suivit de "()", soit on met le mot clé "function" suivit d'un nom (sans parenthèses). Puis on met le contenu de la fonction entre crochets.

Remarque 1 : on ne doit pas mettre à la fois le mot clé "function" et les parenthèses, bien que certains shells récents l'acceptent.

Remarque 2 : il n'y a pas d'importance à utiliser l'une ou l'autre syntaxe, mais la syntaxe avec les parenthèses est plus portable avec les très vieux shells.

Voici la syntaxe :

# declaration de la fonction
nom_de_la_fonction()
# ou : function nom_de_la_fonction
{ actions }

# programme principal
...
actions
...
nom_de_la_fonction # sans parentheses
nom_de_la_fonction $variable # si on doit passer un parametre a la fonction
variable=$? # recupere le resultat de la fonction
...
actions
...

Et comme rien ne vaut un exemple, le voici. Dans cet exemple, on déclare deux fonctions ; l'une calcule le carré d'un nombre, l'autre sa factorielle.

#!/bin/bash
# utilisation des fonctions

function carre
{
  return $[ $1 * $1 ];
}

function factorielle
{
  local x=$1
  local resultat=1
  while [ $x -ge 1 ]; do
  resultat=$[ $x * $resultat ]
  let $[ x-= 1 ];
  done
  return $resultat;
}

# programme principal
echo -n "Tapez un nombre positif : "
read nb
carre $nb ; CARRE=$?	# execute la fonction et recupere la valeur
echo "nb * nb = $CARRE"
factorielle $nb ; FACTORIELLE=$? 	# execute la fonction et recupere la valeur
echo "factorielle : $nb! = $FACTORIELLE"

Ce qui nous donne à l'écran :

$ ./test.sh
Tapez un nombre positif : 5
nb * nb = 25
factorielle : 5! = 120

On remarque bien que le programme principal est beaucoup plus lisible que si on n'avait pas fait appel aux fonctions. Et bien sûr, si on doit faire appel plusieurs fois à la même fonction, l'interêt est encore plus évident.


Pour aller plus loin

Nous avons fait le tour de toutes les principales fonctionnalités des scripts bash. Pour aller plus loin, je vous laisse chercher sur le net, ou dans des livres. Je vous donne quand même les deux liens suivants qui m'ont beaucoup aidé lors de mon apprentissage des scripts (principalement labo-linux). Ils ne vous apprendront peut-être pas beaucoup plus de choses que ce cours, mais les choses sont présentées différemment, et seront peut-être plus claires pour vous.


Bonne programmation !