Table des matières

Scripts en bash

À l'heure des interfaces graphiques, il peut paraitre inutile d'apprendre à programmer avec un shell, tout comme avec les batch files du DOS, mais, par exemple, il y a beaucoup d'administrateurs qui préfèrent exécuter leurs tâches par ces scripts : efficacité et rapidité. C'est une raison pour laquelle Microsoft à développé de nouvelles fonctionnalités et commandes dans son interpréteur livré avec Windows .NET. Comme ils ont mentionné : « DOS n'est pas mort, il était seulement en état de veille. » De toutes façons, ici on parle du bash !

Pourquoi ne pas utiliser ce qui est déjà là ? Bash est l'interpréteur de commandes installé par défaut par la majorité des distributions Linux, alors pourquoi charger un interprteur différent qui prendra de la mémoire de plus inutilement ? Là, prêt à utiliser en tout temps.

De plus, la puissance de l'interpréteur se révèle assez rapidement lorsqu'on l'utilise. Beaucoup plus avancé que le langage du MS-DOS par exemple, les possibilités sont virtuellement illimités. Il est même possible de graver un disque à l'aide d'un script bash.

Avant de commencer

Il faut noter que sous les systèmes d'exploitation Unix-like, il n'y a pas nécessairement d'extentions de fichiers. Par exemple, dans les scripts Windows, les fichiers doivent se terminer soit par .cmd ou par .bat. Ici, il faudra changer les attributs du fichier avec chmod pour le rendre exécutable. Vous pouvez ajouter des extentions aux fichiers, mais ce sera de façon personnelle, car le système d'exploitation ne le prendra pas en compte. Un script Perl peut terminer par .pl ou .cgi par exemple.

Aussi, sous Linux le répertoire courant ne fait pas parti du chemin de recherche. Pour exécuter un script, il faudra préciser le répertoire courant :

$ ./script

Ou bien modifier le chemin de recherche :

$ set PATH=$PATH:<nouveau_chemin>
$ set PATH=$PATH:/home/johndoe

Créer un script

Pour créer un premier script, il faut généralement un éditeur de texte. vi offert avec la plupart des systèmes d'exploitation Unix-like, peut très bien faire l'affaire.

$ vi scriptbash

À la première ligne du script, il faut indiquer sur quel shell il doit être interprété :

#!/bin/bash

Les commentaires

Commençons par le plus simple. Pour bien autodocumenter le script, il est fortement suggéré d'appliquer les commentaires aux bons endroits, surtout si le script fait plusieurs pages. Il n'y a qu'une seule façon de produire des commentaires et c'est en utilisant le caractère dièse (ou carré) : #. Dès que ce caractère est placé sur une ligne quelconque, tout est ignoré à la suite de celui-ci.

#=========================================================#
# VARIABLES                                               #
#=========================================================#
choix=1            # option entrée par l'utilisateur
proc_actif=0       # détermine s'il y a des processus actifs

Commandes incluses

Saisie

La commande read permet de faire la saisie d'un utilisateur et la placer dans une variable.

Syntaxe

read [-t timeout] [-p prompt] variable

Exemple

read choix
read -p "Entrez un choix : " choix

La condition

Il faut utiliser le if pour tester les variables.

Exemple

if expr
then
  instruction
elif expr
then
  instruction2
else
  instruction3
fi

La ligne du if peut s'écrire if expr; then en n'oubliant pas le point-virgule. Même principe avec la ligne du elif : elif expr; then.

Voici le tableau des différentes switches pour faire les tests de nombres dans le format if [$nbparam -eq 1] (à titre d'exemple) :

switch équivalent Signification
-eq = égal
-ne <> Différent
-lt < Inférieur
-le <= Inférieur ou égal
-gt > Plus grand
-ge >= Plus grand ou égal

Le tableau pour comparer les chaînes if [$chaine1 == $chaine2] :

Test Signification
-n Est une chaîne (non nulle)
== Égales
!= Différentes
< Vrai si chaîne1 se trouve avant chaine2
> Vrai si chaîne1 se trouve après chaine2

Et finalement, pour gérer les fichiers :

switch Signification
-f Le fichier existe
-d Le répertoire existe
-s Fichier a des données

Choix conditionnels

La commande case permet de faire plusieurs tests de valeurs sur le contenu d'une même variable. Notez le esac qui termine le case.

Exemple

read reponse
case $reponse in
  [oO]) echo "Vous avez dit oui"
        echo "Appuyez sur [N]";;
  [nN]) echo "Vous avez dit non"
        echo "Choix erroné";;
esac

Fonctions

Pour créer des fonctions, c'est simple, suffi de les déclarer avant leur appel, donc, préférablement au début du script.

#!/bin/bash
 
function nom_de_la_fonction () {
  instruction1
  instruction2
  instructionn
}
 
instructions
nom_de_la_fonction   # appel de la fonction
instructions
exit

Paramètres positionnels

Ce sont les paramètres entrés lors du lancement du script :

$ lescript param1 param2 param3 paramn [...]

La variable $# contient le nombre de paramètres entrés. Pour avoir accès aux paramètres, utiliser les variables $0 (script lui-même), $1, $2, $3, $4, etc.

Terminer le script

Pour terminer le script et en sortir, il faut placer un exit. Ce sera soit à la fin du script, soit là où il est nécessaire.

Spécificités

Écrire la sortie d'une commande dans un fichier

LOGFILE=/tmp/log
command | tee -a $LOGFILE

Faire un saut de ligne dans un fichier

echo $'\r' >> $LOGFILE

Exemple d'un script

L'exemple suivant peut être utile pour voir un peu la structure d'un script écrit en bash. L'objectif du script, c'est de permettre l'effacement d'un fichier, en le plaçant dans un répertoire créé /corb.dir. Ce dernier, comme son nom l'indique, sert de corbeille.

#!/bin/bash
 
#######################################################
# Script : sdel ver.: 0.5.0.1                         #
# Auteur : Stephane Gariépy                           #
# Date   : 19 décembre 2005                           #
# But    : Efface (ou déplace) un fichier dans un     #
#          répertoire Corbeille (~/corb.bin) spécifié #
#          en paramètre.                              #
#######################################################
 
function afficher_aide_fr {
  echo "       "
  echo "SYNTAXE  : sdel [SPECFICH][-h]"
  echo "SPECFICH : Représente une spécification de fichier selon la syntaxe"
  echo "           suivante : [chemin]/[nomfich]"
  echo "Exemple 1 : sdel -h  (affiche cet écran d'aide)"
  echo "Exemple 2 : sdel toto (Déplace le fichier toto dans ~/corb.dir)"
  echo "   "
  read -p "Appuyez sur une touche pour quitter..."
}
 
function afficher_aide_en {
  echo "    "
  echo "SYNTAX   : sdel [SPECFICH][-h]"
  echo "SPECFICH : Represents a file specification using the following syntax :"
  echo "           [path]/[filename]"
  echo "Example 1 : sdel -h (Shows this help screen)"
  echo "Example 2 : sdel toto (Moves toto to the recycle bin ~/corb.dir)"
  echo "          "
  read -p "Hit any key to quit..."
}
 
function validation_langue {
  case $rep_langue in
    [fF]) afficher_aide_fr;;
    [eE]) afficher_aide_en;;
       *) choix_langue;;
  esac
  return
}
 
function choix_langue {
  clear
  read -p "Quelle langue préférez-vous ? / Which language do you prefer ? (F)rançais ou/or (E)nglish ?" rep_langue
  validation_langue
  return
}
 
function deplacer_fichier {
  mv $specfich ~/corb.dir
  return
}
 
function demander_ecraser_fichier {
  read -t 10 -p "Le fichier $fichier existe dans ~/corb.dir.  Voulez-vous écraser ?" rep_ecraser
 
  case $rep_ecraser in
    [oOyY]) deplacer_fichier;;
      [nN]) exit;;
         *) exit;;
  esac
  return
}
 
function creer_corbeille {
  mkdir ~/corb.dir
  return
}
 
specfich=$1
fichier=${1##*/}
corbeille="~/corb.dir"
corb_fich="~/corb.dir/$fichier"
 
if [ $# -eq 1 ]             #vérification du nb de param
then
  if [ $1 == "-h" ]         #vérification du param -h
  then
    choix_langue
  else
    if [ -f $1 ]                         #fichier $1 existe ?
    then
      if [ -d ~/corb.dir ]
      then
 
        if [ -f ~/corb.dir/$fichier ]
        then
          demander_ecraser_fichier
        else
          deplacer_fichier
        fi
 
      else #corb.dir n'existe pas
        creer_corbeille
        deplacer_fichier
      fi
    else
      echo "Fichier $1 introuvable."
    fi
  fi
else
  choix_langue
fi

# Renommer des fichiers avec espaces

$ for f in *\ *; do mv "$f" "${f// /_}"; done