33.5. Un script s'appelant lui-même (récursion)

Un script peut-il s'appeler récursivement ? En fait, oui.

Exemple 33.8. Un script (inutile) qui s'appelle récursivement

#!/bin/bash
# recurse.sh

# Un script peut-il s'appeler récursivement ?
# Oui, mais est-ce d'une utilité quelconque ?
# Voir le script suivant.

ECHELLE=10
VALMAX=9

i=$RANDOM
let "i %= $ECHELLE"  # Génère un nombre aléatoire entre 0 et $VALMAX.

if [ "$i" -lt "$VALMAX" ]
then
  echo "i = $i"
  ./$0       #  Le script lance récursivement une nouvelle instance de lui-même.
fi           #  Chaque fil du script fait de même jusqu'à ce que la valeur
             #+ générée $i soit égale à $VALMAX.

# Utiliser une boucle "while" au lieu d'un test "if/then" pose des problèmes.
# Expliquez pourquoi.

exit 0

# Note :
# -----
# Ce script doit avoir le droit d'exécution pour fonctionner correctement.
# C'est le cas même s'il est appelé par une commande "sh".
# Expliquez pourquoi.

Exemple 33.9. Un script (utile) qui s'appelle récursivement

#!/bin/bash
# pb.sh : carnet de téléphones.

# Écrit par Rick Boivie et utilisé avec sa permission.
# Modifications par l'auteur du guide ABS

MINARGS=1       # Le script a besoin d'au moins un argument.
FICHIERDONNEES=./carnet_telephone
          #  Un fichier de données du répertoire courant, nommé
          #+ "carnet_telephone", doit exister.
NOMPROG=$0
E_SANSARGS=70   # Erreur lorsque sans arguments.

if [ $# -lt $MINARGS ]; then
      echo "Usage : "$NOMPROG" donnees-a-rechercher"
      exit $E_SANSARGS
fi


if [ $# -eq $MINARGS ]; then
      grep $1 "$FICHIERDONNEES"
      # 'grep' affiche un message d'erreur si $FICHIERDONNEES n'existe pas.
else
      ( shift; "$NOMPROG" $* ) | grep $1
      # Le script s'appelle récursivement.
fi

exit 0        #  Le script sort ici.
              #  On peut mettre des commentaires sans '#' et des données après
              #+ ce point.

# ------------------------------------------------------------------------
# Exemple d'un carnet d'adresses :

John Doe        1555 Main St., Baltimore, MD 21228          (410) 222-3333
Mary Moe        9899 Jones Blvd., Warren, NH 03787          (603) 898-3232
Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678
Zoe Zenobia     4481 N. Baker St., San Francisco, SF 94338   (415) 501-1631
# ------------------------------------------------------------------------

$bash pb.sh Roe
Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678

$bash pb.sh Roe Sam
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678

#  Lorsqu'au moins un argument est passé au script, celui-ci n'affiche *que*
#+ le(s) ligne(s) contenant tous les arguments.

Exemple 33.10. Un autre script (utile) qui s'appelle récursivement

#!/bin/bash
# usrmnt.sh, écrit par Anthony Richardson
# Utilisé avec sa permission.

# usage :       usrmnt.sh
# description : monte un périphérique, l'utilisateur l'appelant doit être listé
#               dans le groupe MNTUSERS dans le fichier /etc/sudoers.

# -----------------------------------------------------------------
# C'est un script usermount qui se relance lui-même en utilisant sudo.
# Un utilisateur avec seulement les bons droits doit taper

#   usermount /dev/fd0 /mnt/floppy

# au lieu de

#   sudo usermount /dev/fd0 /mnt/floppy

#  J'utilise cette même technique pour tous mes scripts sudo
#+ parce que je la trouve convenable.
# -----------------------------------------------------------------

#  Si la variable SUDO_COMMAND n'est pas initialisée, nous ne sommes pas exécutés
#+ à partir de sudo, donc nous le relançons nous-même. Passez les identifiants
#+ réels de l'utilisateur et du groupe...

if [ -z "$SUDO_COMMAND" ]
then
   mntusr=$(id -u) grpusr=$(id -g) sudo $0 $*
   exit 0
fi

# Nous arriverons ici que si le script a été exécuté via sudo
/bin/mount $* -o uid=$mntusr,gid=$grpusr

exit 0

# Notes supplémentaires (de l'auteur de ce script) :
# --------------------------------------------------

# 1) Linux permet l'option "users" dans le fichier /etc/fstab
#    de façon à ce que tout utilisateur puisse monter un media modifiable.
#    Mais, sur un serveur, j'aime autoriser seulement quelques accès
#    individuels au média modifiable. Je trouve qu'utiliser sudo me donne
#    plus de contrôle.

# 2) Je trouve aussi sudo plus convenable pour accomplir cette tâche plutôt
#    qu'utiliser les groupes.

# 3) Cette méthode donne à chacun les bons droits (accès root) pour la commande
#    mount, donc faites bien attention à qui vous donnez accès. Vous pouvez
#    obtenir un contrôle plus fin sur les accès de montage en utilisant cette
#    même technique dans des scripts séparés : mntfloppy, mntcdrom et mntsamba.

[Attention]

Attention

Trop de niveaux de récursivité peut surcharger la pile du script, causant une erreur de segmentation (segfault).