Sommaire
if then elif else fi
Un processus ou une fonction peuvent retourner un entier (codé sur 8 bits, donc une valeur comprise entre 0 et 255). 0 signifie que le processus s’est terminé en exécutant correctement son code, par défaut si on ne force pas le code de retour c’est cette valeur qui est utilisée. A noter que c’est le développeur qui détermine le code de retour et il peut utiliser exit
pour sortir du programme en précisant le code de retour (exemple : exit 0
ou exit 200
. La valeur de retour du programme se trouve dans la variable $?
. Elle est modifiée à chaque appel d’une commande.
Dans une logique “booléenne” le zéro est true
et 1 -> 255 false
. [
est en fait une commande Linux et correspond à la commande test
(faire un man [
pour voir les options). La commande [
doit forcément se terminer par ]
, ce qui n’est pas le cas de la commande test
. Lorsque cette commande est appelée elle va évaluer l’expression passée en paramètre et retourner 0
si l’expression est true
ou 1
si l’expression est false
. if
va ensuite tester le code de retour de [
pour déterminer si la commande a retourné true
ou false
.
myreturn() { if [ $# -gt 2 ] then return 0 else return 1 fi } a=2 [ "$a" = 2 ] && echo "ca vaut 2" ca vaut 2 a=8 [ "$a" != 2 ] && echo "ca vaut pas 2" ca vaut pas 2 myreturn 1 2 3 && echo "OK" OK (! myreturn 1 3) && echo "BAD" BAD myreturn 1 3 || echo "BAD" BAD myreturn 1 2 3 || echo "Nothing" if myreturn 1 2 3 then echo "IF: OK" else echo "IF: BAD" fi IF: OK myreturn 1 2 3 err=$? echo $err 0 myreturn 12 echo $? 1 echo $? 0 echo $? 0
L’utilisation du &&
et du ||
est à utiliser avec précaution.
Si je fais cmd1 && cmd2
, la commande cmd2
est exécutée si et seulement si la commande cmd1
a retourné 0
( => true
).
Si je fais cmd1 || cmd2
, la commande cmd2
est exécutée si et seulement si la commande cmd1
a retourné une valeur différente de 0
( => false
).
On peut aussi utiliser l’opérateur unaire not, symbolisé par !
et combiner les commandes en utilisant des parenthèses. Exemple :
cmd1 && (! cmd2 || cmd3 )
cmd1() { echo "cmd1($1)" return $1 } cmd2() { echo "cmd2($1)" return $1 } cmd3() { echo "cmd3($1)" return $1 } cmd1 0 && (! cmd2 0 || cmd3 0 ) cmd1(0) cmd2(0) cmd3(0) cmd1 0 && (! cmd2 0 || cmd3 1 ) cmd1(0) cmd2(0) cmd3(1) cmd1 0 && (! cmd2 1 || cmd3 0 ) cmd1(0) cmd2(1) cmd1 0 && (! cmd2 1 || cmd3 1 ) cmd1(0) cmd2(1) cmd1 1 && (! cmd2 0 || cmd3 0 ) cmd1(1) cmd1 1 && (! cmd2 0 || cmd3 1 ) cmd1(1) cmd1 1 && (! cmd2 1 || cmd3 0 ) cmd1(1) cmd1 1 && (! cmd2 1 || cmd3 1 ) cmd1(1)
“case” vs “if then elif elif … else fi”
if then elif else fi
Utilisation de la commande [
func_ifandco() { local a=$1 if [ "$a" = 12 ] then echo "$a est douze" elif [ "$a" = 14 ] then echo "$a est quatorze" else echo "$a n'est pas douze ou quatorze" fi } func_ifandco 12 12 est douze func_ifandco 15 15 n'est pas douze ou quatorze func_ifandco 14 14 est quatorze
Utilisation de la commande test
func() { if test $# -gt 2 then printf "%05d %s\n" $# "coucou" else echo "not enough" fi } func 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 00019 coucou func 1 2 not enough
case
func_case() { local a=$1 case "$a" in 12) echo " $a est douze" ;; 14) echo " $a est quatorze" ;; *) echo " $a n'est pas douze ou quatorze" esac } func_case 63 63 n'est pas douze ou quatorze func_case 14 14 est quatorze func_case 12 12 est douze
func_answer() { while /bin/true do echo -n "$1? [y/n]: " read ans case $ans in [yY]) echo "you answer is $ans" return 0 ;; [nN] ) echo "you answer is $ans" return 1 ;; *) echo "Invalid answer, expecting Y or N" ;; esac done } if func_answer "Do you want to restart service" then echo "restarting service" else echo "restart canceled" fi Do you want to restart service? [y/n]: y you answer is y restarting service
boucles
On notera dans ces exemples l’importance, une fois de plus, de positionner correctement les "
.
On peut passer à une fonction ou un programme plusieurs paramètres. Pour récupérer la valeurs de ces paramètres il faut utiliser :
$0
: correspond au nom du programme (de la manière dont il a été appelé, notamment incluant lepath
s’il a été spécifié).$1 ... $n
: la liste des paramètres$*
et$@
: le tableau contenant tous les paramètres. Attention le comportement des deux est différent notamment lorsqu’on les utilise avec des"
."$*"
correspond à :"$1 $2 $3 ...$n"
"$@"
correspond à :"$1" "$2" "$3" ... "$n"
si j’appelle la commande mkdir -p /var/tmp/foo/bar "/var/tmp/espace ici"
:
$0
:mkdir
$1
:-p
$2
:/var/tmp/foo/bar
$3
:/var/tmp/espace ici
for et utilisation de $*
, $@
avec ou sans "
my_loop1() { echo "my_loop1: nb param = $#" local count=1 for i in $* do echo "param($count) = '$i' " count=$(($count + 1)) done } my_loop2() { echo "my_loop2: nb param = $#" local count=1 for i in "$@" # => "$1" "$2" "$3" ... do echo "param($count) = '$i' " count=$(($count + 1)) done } my_loop3() { echo "my_loop1: nb param = $#" local count=1 for i in "$*" # "$1 $2 $3 ..." do echo "param($count) = '$i' " count=$(($count + 1)) done } my_loop1 1 2 3 jvnfjvnf vfjnvfjnvfjn my_loop1: nb param = 5 param(1) = '1' param(2) = '2' param(3) = '3' param(4) = 'jvnfjvnf' param(5) = 'vfjnvfjnvfjn' a="A B C" my_loop1 $a my_loop1: nb param = 3 param(1) = 'A' param(2) = 'B' param(3) = 'C' my_loop1 "$a" my_loop1: nb param = 1 param(1) = 'A' param(2) = 'B' param(3) = 'C' my_loop1 "ABC DEF" "GHI JKL" my_loop1: nb param = 2 param(1) = 'ABC' param(2) = 'DEF' param(3) = 'GHI' param(4) = 'JKL' my_loop2 $a my_loop2: nb param = 3 param(1) = 'A' param(2) = 'B' param(3) = 'C' my_loop2 "$a" my_loop2: nb param = 1 param(1) = 'A B C' my_loop2 "ABC DEF" "GHI JKL" my_loop2: nb param = 2 param(1) = 'ABC DEF' param(2) = 'GHI JKL' my_loop3 $a my_loop1: nb param = 3 param(1) = 'A B C' my_loop3 "$a" my_loop1: nb param = 1 param(1) = 'A B C' my_loop3 "ABC DEF" "GHI JKL" my_loop1: nb param = 2 param(1) = 'ABC DEF GHI JKL'
for
Utilisation d’une commande (seq
qui renvoie une séquence de nombres) :
for i in $(seq 1 10) do echo $i done 1 2 3 4 5 6 7 8 9 10
Lister des fichiers :
for i in *.xml do echo $i done a.xml b.xml c.xml d.xml
Commande avec un pipe :
for i in $(ls *.xml | cut -d '.' -f 1) do echo $i done a b c d
commande ls :
for i in $(ls *.xml) do echo ${i%.xml} done a b c d
“à la C” :
for((i=0;i<6;i++)) do echo $i done 0 1 2 3 4 5 6
while
count=5 while [ $count -gt 0 ] do echo $count count=$(($count - 1)) done 5 4 3 2 1
break
permet de sortir d’une boucle (for
ou while
)
count=5 while true do echo $count count=$(($count - 1)) [ $count -eq 0 ] && break done 5 4 3 2 1
continue
permet d’itérer sur une boucle (for
ou while
)
count=11 while true do count=$(($count - 1)) [ $count -eq 0 ] && break if [ $count -gt 5 ] then echo "##$count##" elif [ $count -eq 3 ] then continue else echo "//$count//" fi done ##10## ##9## ##8## ##7## ##6## //5// //4// //2// //1//