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 le path 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//