![[Photo of the Authors]](../../common/images/KatjaAndGuido.jpg) 
 
    original in en Katja and Guido Socher
en to fr Éric Jullien
Katja est l'éditeur allemand de LinuxFocus. Elle aime Tux, les films, la photographie et la mer. Sa page personnelle se trouve ici.
Guido est un vieux fan de Linux. Il apprécie Linux car il est conçu par des gens honnètes et ouverts. C'est d'ailleurs la raison pour laquelle on l'appelle "Logiciel Ouvert"). Sa page personnelle se trouve à linuxfocus.org/~guido.
![[Illustration]](../../common/images/illustration216.jpg) 
 
    
    #!/bin/sh 
   
    Les caractères #! indiquent au système 
 que l'argument suivant est le programme à utiliser pour exécuter
    ce fichier.
    Ici, nous utilisons le shell /bin/sh. varname=valuePour récupérer la valeur de la variable, il suffit d'écrire le signe dollar devant le nom de la variable :
#!/bin/sh # affecte une valeur a la variable : a="Bonjour le Monde" # affiche le contenu de la variable "a" : echo "La valeur de A est :" echo $aTapez ces lignes dans un éditeur de texte et enregistrez-les sous le nom "premier". Rendez ensuite le script exécutable en tapant chmod +x premier dans un shell et lancez-le par ./premier
La valeur de A est : Bonjour le MondeIl peut arriver qu'il y ait confusion entre les noms de variables et le reste du texte :
num=2 echo "ceci est le $numeme"Ce script ne va pas afficher "ceci est le 2eme" mais "ceci est le " car le shell recherche une variable nommée numeme qui n'a pas de valeur définie. Pour indiquer au shell que nous faisons référence à la variable num il faut utiliser les accolades :
num=2
echo "ceci est le ${num}eme"
    Cette fois le script affiche ce que nous attendons : 
| Syntaxe de la commande | But | 
|---|---|
| echo "un texte" | affiche un texte sur l'écran | 
| ls | liste des fichiers | 
| wc -l fichier wc -w fichier wc -c fichier | compte les lignes du fichier, ou compte les mots du fichier, ou compte le nombre de caractères | 
| cp fichier_source fichier_dest | copie le fichier_source vers le fichier_dest | 
| mv ancien_nom nouveau_nom | renomme ou déplace le fichier | 
| rm fichier | efface le fichier | 
| grep 'pattern' fichier | cherche des
          chaînes de caratères dans 
         un fichier Exemple: grep 'searchstring' file.txt | 
| cut -c num_colonne fichier | récupère les données issues de 
colonnes de textes à largeur fixe. Exemple : récupère les caractères des positions 5 à 9 cut -b5-9 file.txt Ne pas confondre cette commande avec la commande cat, qui a une utilisation totalement différente. | 
| cat file.txt | écrit le contenu du fichier file.txt sur la sortie standard stdout (qui est par défaut votre écran) | 
| file fichier | décrit le type de fichier | 
| read var | attend une frappe de l'utilisateur en entrée et stocke cette valeur dans une variable (var) | 
| sort file.txt | trie les lignes du fichier file.txt | 
| uniq, | retire les lignes en double, utilisé parallèlement à
sort, puisque uniq ne retire
        que les doublons sur des lignes consécutives. Exemple : sort file.txt | uniq | 
| expr | pour faire des maths dans le shell Exemple: ajouter 2 et 3 expr 2 "+" 3 | 
| find | recherche de fichier Exemple : rechercher un nom : find . -name nom_fichier -print Cette commande possède énormément d'options et de possibilités différentes, rendant leur description impossible dans cet article. | 
| tee | écrit simultanément des données vers stdout (l'écran) et dans un fichier. Elle s'utilise habituellement de cette manière : commande | tee fichier_de_sortie Affiche la sortie de la commande à l'écran et l'écrit dans le fichier_de_sortie. | 
| basename fichier | retourne le nom du fichier sans le chemin
         d'accès. Exemple : basename /bin/tux retourne seulement tux | 
| dirname fichier | renvoie le nom du répertoire d'un fichier sans préciser le nom de ce
	fichier Exemple: dirname /bin/tux retourne /bin | 
| head fichier | affiche les premières lignes du début d'un fichier. | 
| tail fichier | affiche les dernières lignes de la fin d'un fichier | 
| sed | sed est à la base un programme de recherche et de
remplacement . Il lit le texte de 
         l'entrée standard (depuis un "pipe", par exemple)
         et écrit le résultat sur la sortie standard
         (stdout, l'écran).
         Le modèle à rechercher est
        une expression régulière (voir la section 
       Réferences). Ce modèle de recherche ('pattern') ne doit pas être confondu avec la syntaxe des 'wildcards' du shell. Par exemple, pour remplacer dans un texte la chaîne de caractères linuxfocus par la chaîne LinuxFocus, exécutez : cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file Cette commande remplace la première occurrence de la chaîne linuxfocus par la chaîne LinuxFocus. S'il y a des lignes contenant plusieurs fois la chaîne linuxfocus et que vous vouliez toutes les remplacer, tapez : cat text.file | sed 's/linuxfocus/LinuxFocus/g' > newtext.file | 
| awk | La plupart du temps, awk est utilisé pour 
extraire des blocs d'une ligne de texte.
       Le séparateur par défaut est l'espace.
      
     Utilisez l'option -F pour définir un autre
    séparateur. 
   cat fichier.txt | awk -F, '{print $1 "," $3 }'  Ici, la virgule (,) est utilisée 
comme séparateur et nous affichons les première et  troisième
($1$3) colonnes. Si fichier.txt contient les lignes suivantes :Adam Bor, 34, India Kerry Miller, 22, USALe résultat sera : Adam Bor, India Kerry Miller, USAVous pouvez faire beaucoup plus avec awk mais ce qui précède est l'usage le plus courant. | 
    grep "hello" file.txt | wc -l
    Cette commande recherche les lignes contenant la chaîne de 
 caractères hello dans le fichier file.txt 
et compte le nombre de lignes concernées. find . -mtime -1 -type f -printrecherche tous les fichiers qui ont été modifiés dans les dernières 24 heures ( -mtime -2 aurait signifié 48 heures). Si on veut regrouper tous ces fichiers dans une archive 'tar' (fichier.tar), la syntaxe de la commande tar est :
tar xvf fichier.tar fich1 fich2 ...Au lieu de taper la totalité, vous pouvez combiner ces deux commandes (find et tar) en utilisant les backticks. Tar va alors regrouper tous les fichiers trouvés par find :
#!/bin/sh
# Les ticks sont des guillemets simples inversés (`) 
# et non des guillemets simples (')
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
    if ....; then .... elif ....; then .... else .... fiTrès souvent, une commande particulière, appelée test, est utilisée à l'intérieur d'une instruction "if" pour comparer des chaînes de caractères ou tester l'existence d'un fichier, ses permissions,etc.
[ -f "un_fichier" ] : Teste si "un_fichier" est un fichier [ -x "/bin/ls" ] : Teste si "/bin/ls" existe et est exécutable [ -n "$var" ] : Teste si la variable $var n'est pas vide [ "$a" = "$b" ] : Teste si les variables "$a" et "$b" sont égalesExécutez la commande man test et vous obtiendrez la longue liste de tous les opérateurs de test sur les comparaisons et les fichiers.
#!/bin/sh if [ "$SHELL" = "/bin/bash" ]; then echo "Votre shell de login est le bash (bourne again shell)" else echo "Votre shell de login n'est pas bash mais $SHELL" fiLa variable $SHELL contient le nom du shell de login et c'est ce que nous testons ici en la comparant avec la chaîne de caractères "/bin/bash"
[ -f "/etc/shadow" ] && echo "Cet ordinateur utilise les shadow passwords"La syntaxe && peut être utilisée comme un raccourci de l'instruction if. La partie droite de l'instruction est exécutée si la partie gauche est vraie. On peut lire cette instruction comme une instruction "AND" (ET). Ainsi, l'exemple devient : "le fichier /etc/shadow existe ET la commande echo est exécutée". L'opérateur "OR" (OU) (dont le symbole est ||) est également disponible. Voici un exemple :
#!/bin/sh
mailfolder=/var/spool/mail/james
[ -r "$mailfolder" ] || { echo "Je ne peux pas lire $mailfolder" ; exit 1; }
echo "$mailfolder a recu un courrier de :"
grep "^From " $mailfolder
   Ce script teste tout d'abord s'il peut lire un mailfolder ("dossier de
   courrier") précis.
   Si c'est le cas, il affiche les lignes "From" du dossier.
S'il ne peut lire le fichier $mailfolder, alors
   l'opérateur "OR" entre en action.
   En bon français, vous liriez cette ligne de code comme 
   "Dossier de courrier lisible ou sortie du programme"
   Le problème, ici, c'est qu'après OR on ne peut mettre qu'une 
seule commande, mais il nous en faut deux : case ... in ...) action ;; esacPrenons un exemple. La commande file peut indiquer le type d'un fichier :
file lf.gzretourne :
lf.gz: gzip compressed data, deflated, original filename, last modified: Mon Aug 27 23:09:18 2001, os: UnixNous allons l'utiliser pour écrire un script nommé smartzip qui peut décompresser automatiquement des fichiers bzip2, gzip et zip :
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
    unzip "$1" ;;
"$1: gzip compressed"*)
    gunzip "$1" ;;
"$1: bzip2 compressed"*)
    bunzip2 "$1" ;;
*) error "Le fichier $1 ne peut pas etre décompressé avec smartzip";;
esac
    Vous remarquerez que nous avons utilisé ici une nouvelle 
variable appelée $1. Cette variable contient le premier
    argument donné au programme. Supposons que nous 
exécutions
    select var in ... ; do break done .... maintenant $var peut être utilisé ....Voici un exemple :
#!/bin/sh
echo "Quel est votre OS préféré ?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
        break
done
echo "Vous avez sélectionné $var"
    Voici ce que fait ce script :
Quel est votre OS préféré ? 1) Linux 2) Gnu Hurd 3) Free BSD 4) Other #? 1 Vous avez sélectionné LinuxDans le shell, vous disposez des instructions de boucles suivantes :
while ...; do .... doneLa boucle while va être exécutée tant que l'expression testée est vraie. Le mot clé break peut être utilisé pour quitter la boucle n'importe quand. Avec le mot clé continue, la boucle se poursuit à l'itération suivante en ignorant le reste du corps de la boucle.
for var in ....; do .... doneLe code suivant affiche les lettres de A à C à l'écran :
#!/bin/sh for var in A B C ; do echo "var est $var" doneVoici un exemple de script plus utile, appelé showrpm, qui affiche un résumé du contenu de plusieurs paquetages RPM :
#!/bin/sh
# liste un résumé du contenu de plusieurs paquetages RPM
# USAGE: showrpm rpmfile1 rpmfile2 ...
# EXEMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
  if [ -r "$rpmpackage" ];then
    echo "=============== $rpmpackage ==============="
    rpm -qi -p $rpmpackage
  else
    echo "ERREUR: showrpm ne peut pas lire le fichier $rpmpackage"
  fi
done
    Vous noterez ci-dessus, l'apparition d'une nouvelle variable 
    spéciale, $*, qui contient la liste de tous les
    arguments de la ligne de commande. Si vous exécutez 
    #!/bin/sh echo *.jpgCeci affichera "mail.jpg tux.jpg".
#!/bin/sh echo "*.jpg" echo '*.jpg'Ce programme va afficher deux fois "*.jpg".
#!/bin/sh echo $SHELL echo "$SHELL" echo '$SHELL'Ce programme affichera :
/bin/bash /bin/bash $SHELLEnfin il est possible de retirer la signification particulière de n'importe quel caractère en le faisant précéder d'un anti-slash :
echo \*.jpg echo \$SHELLQui affichera :
*.jpg $SHELLLes "Here documents"
#!/bin/sh
# Si nous avons moins de 3 arguments, on affiche le message d'aide
if [ $# -lt 3 ] ; then
cat <<HELP
ren -- renomme plusieurs fichiers en utilisant des expressions regulières de sed
USAGE: ren 'regexp' 'replacement' files...
EXEMPLE: renomme tous les fichiers *.HTM en *.html:
  ren 'HTM$' 'html' *.HTM
HELP
  exit 0
fi
OLD="$1"
NEW="$2"
# la command shift retire un argument de la liste des arguments de 
# la ligne de commande
shift
shift
# la variable $* contient maintenant tous les fichiers.
for file in $*; do
    if [ -f "$file" ] ; then
      newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
      if [ -f "$newfile" ]; then
        echo "ERREUR: $newfile existe deja"
      else
        echo "fichier $file renommé en $newfile ..."
        mv "$file" "$newfile"
      fi
    fi
done
    Ce script est le plus complexe écrit jusqu'ici.
Étudions-le plus en détail.
La première instruction if teste si nous avons bien fourni au 
programme un minimum de trois arguments de ligne de commande (la 
    variable spéciale $# contient 
    le nombre d'arguments). Si ce n'est pas le cas,
    le texte d'aide est envoyé à la commande 
cat, qui, à son tour, l'affiche sur 
l'écran. Une fois cette aide affichée, nous 
sortons du programme. 
Si trois arguments ou plus, sont présents, le premier est
    affecté à la variable OLD et le second 
    à la variable NEW. Nous éliminons ensuite
    ces deux arguments de la ligne de commande, par la commande 
shift, pour placer le troisième argument en première position dans
$*. Avec $* nous entrons dans la boucle.
Les arguments dans $* sont affectés un par un à la variable $file. 
Nous vérifions d'abord que le fichier existe 
puis nous construisons un nouveau nom de fichier en utilisant le
"chercher-remplacer" de sed.
Les "backticks" sont utilisés pour affecter le résultat à la variable 
newfile.
Nous avons maintenant tout le néssaire : l'ancien nom de fichier et le
nouveau. Ceux-ci vont
être utilisés par la commande mv pour renommer le fichier.
nom_de_la_fonction()
{
 # dans le corps de la fonction, $1 est le 1er argument passé à celle-ci
 # $2 le second ...
 corps de la fonction
}
    Une fonction doit être déclarée au début 
du script, avant toute utilisation. 
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
    cat <<HELP
xtitlebar -- change le nom d'un xterm, gnome-terminal ou d'une konsole kde
USAGE: xtitlebar [-h] "string_for_titelbar"
OPTIONS: -h help texte
EXEMPLE: xtitlebar "cvs"
HELP
    exit 0
}
# en cas d'erreur ou si l'option -h est passée en argument, nous appelons la
# fonction help :
[ -z "$1" ] && help
[ "$1" = "-h" ] && help
# envoie la sequence d'échappement pour changer la barre de titre du xterm :
echo -e "\033]0;$1\007"
#
    Une bonne habitude à prendre est de toujours avoir une aide 
    la plus complète possible dans les scripts.
    Ceci permet à d'autres personnes (vous compris)
de comprendre et d'utiliser le script.
#!/bin/sh
help()
{
  cat <<HELP
ceci est un exemple d'analyseur générique de ligne de commande
USAGE EXEMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
  exit 0
}
while [ -n "$1" ]; do
case $1 in
    -h) help;shift 1;; # appel de la fonction help
    -f) opt_f=1;shift 1;; # la variable opt_f est définie
    -l) opt_l=$2;shift 2;; # -l prend un argument -> décalé de 2
    --) shift;break;; # fin des options
    -*) echo "erreur: il n'existe pas d'option $1. -h pour l'aide";exit 1;;
    *)  break;;
esac
done
echo "opt_f est $opt_f"
echo "opt_l est $opt_l"
echo "premier arg est $1"
echo "2nd arg est $2"
    Essayez-le ! Vous pouvez l'exécuter comme suit :
cmdparser -l hello -f -- -somefile1 somefile2Vous obtenez :
opt_f est 1 opt_l est hello premier arg est -somefile1 2nd arg est somefile2Comment ça marche ? Le script boucle sur la liste de tous les arguments et les compare aux conditions de test de l'instruction case. S'il trouve un argument qui correspond, il positionne alors la variable et décale la ligne de commande d'une position. La convention Unix veut que les options (ce qui commence par un signe moins) soient placées en premier. Vous pouvez indiquer la fin d'une option en inscrivant deux signes moins (--). grep le réclame, par exemple, pour rechercher une chaîne de caractères commençant par un signe moins :
Recherche de -xx- dans le fichier f.txt: grep -- -xx- f.txtNotre analyseur d'option peut également gérer l'option -- comme vous pouvez le voir dans la liste ci-dessus.
cp framework.sh myscriptet inclure les nouvelles fonctionnalités dans "myscript".
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
  cat <<HELP
b2h -- convertit un binaire en décimal.
USAGE: b2h [-h] nombre_binaire
OPTIONS: -h message d'aide
EXAMPLE: b2h 111010
will return 58
HELP
  exit 0
}
error()
{
    # affiche une erreur et quitte le programme
    echo "$1"
    exit 1
}
lastchar()
{
    # retourne le dernier caractère d'une chaîne dans $rval
    if [ -z "$1" ]; then
        # chaîne vide
        rval=""
        return
    fi
    # wc place des espaces derrière la sortie, c'est pourquoi nous utilisons sed
    numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
    # nous coupons le dernier caractère
    rval=`echo -n "$1" | cut -b $numofchar`
}
chop()
{
    # retire le dernier caractère de la chaîne qui est renvoyé dans $rval
    if [ -z "$1" ]; then
        # empty string
        rval=""
        return
    fi
    # wc place des espaces derrière la sortie, c'est pourquoi nous utilisons sed
    numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
    if [ "$numofchar" = "1" ]; then
        # un seul caractère dans la chaîne
        rval=""
        return
    fi
    numofcharminus1=`expr $numofchar "-" 1` 
    # conserve tout, sauf le dernier caractère 
    rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
}
    
while [ -n "$1" ]; do
case $1 in
    -h) help;shift 1;; # appel de la fonction help
    --) shift;break;; # fin des options
    -*) error "error: pas d'option $1. -h pour l'aide";;
    *)  break;;
esac
done
# Programme principal
sum=0
weight=1
# un arg doit être fourni
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"
while [ -n "$binnum" ]; do
    lastchar "$binnum"
    if [ "$rval" = "1" ]; then
        sum=`expr "$weight" "+" "$sum"`
    fi
    #retire la dernière position dans $binnum
    chop "$binnum"
    binnum="$rval"
    weight=`expr "$weight" "*" 2`
done
echo "le binaire $binnumorig est le décimal $sum"
#
    L'algorithme, utilisé dans ce script, prend le poids
    décimal de chaque chiffre (1, 2, 4, 8, 16...),
    en partant du chiffre le plus à droite, et 
    l'ajoute à la somme si le chiffre est un 1. Ainsi, "10"
    se décompose comme suit :
#!/bin/sh
# vim: set sw=4 ts=4 et: 
ver="0.1"
help()
{
    cat <<HELP
rotatefile -- effectue une rotation de nom de fichier
USAGE: rotatefile [-h]  nom_fichier
OPTIONS: -h affiche l'aide
EXEMPLE: rotatefile out
Ceci va, par exemple, renommer out.2 en out.3, out.1 en out.2, out en out.1
et créer un fichier vide out.
Le nombre maximum de fichier est 10
version $ver
HELP
    exit 0
}
error()
{
    echo "$1"
    exit 1
}
while [ -n "$1" ]; do
case $1 in
    -h) help;shift 1;;
    --) break;;
    -*) echo "erreur: pas d'option $1. -h pour l'aide";exit 1;;
    *)  break;;
esac
done
# input check:
if [ -z "$1" ] ; then
 error "ERREUR: vous devez spécifier un fichier, utilisez -h pour l'aide" 
fi
filen="$1"
# rename any .1 , .2 etc file:
for n in  9 8 7 6 5 4 3 2 1; do
    if [ -f "$filen.$n" ]; then
        p=`expr $n + 1`
        echo "mv $filen.$n $filen.$p"
        mv $filen.$n $filen.$p
    fi
done
# renomme le fichier original :
if [ -f "$filen" ]; then
    echo "mv $filen $filen.1"
    mv $filen $filen.1
fi
echo touch $filen
touch $filen
Comment fonctionne le programme ?
     Après avoir vérifié que l'utilisateur a fourni 
un nom de fichier, le programme entre dans une boucle
    décrémentale de 9 à 1. Le fichier 9, est alors
    renommé 10, le fichier 8 est 
    renommé 9,
    et ainsi de suite. A la sortie de la boucle nous renommons 
le fichier original en 1 et nous créons un fichier vide
avec le nom du fichier original.
    sh -x scriptetrangeCette commande lancera le script en affichant toutes les instructions exécutées ainsi que les valeurs des variables et des méta-caractères.
sh -n votre_scriptSi vous ne voyez rien sur votre écran, c'est que votre programme ne contient pas d'erreur de syntaxe.