33.4. Ricorsività

Può uno script richiamare sé stesso ricorsivamente? Certo.

Esempio 33-8. Un (inutile) script che richiama sé stesso ricorsivamente

#!/bin/bash
# recurse.sh

#  Può uno script richiamare sé stesso ricorsivamente?
#  Sì, ma può essere di qualche uso pratico?
#  (Vedi il successivo.)

INTERVALLO=10
VALMAX=9

i=$RANDOM
let "i %= $INTERVALLO"  #  Genera un numero casuale compreso
                        #+ tra 0 e $INTERVALLO - 1.

if [ "$i" -lt "$VALMAX" ]
then
  echo "i = $i"
  ./$0                  #  Lo script genera ricorsivamente una nuova istanza 
                        #+ di sé stesso.
fi                      #  Ogni script figlio fa esattamente la stessa 
                        #+ cosa, finché $i non diventa uguale a $VALMAX.

#  L'uso di un ciclo "while", invece della verifica "if/then", provoca problemi.
#  Spiegate perché.

exit 0

# Nota:
# ----
# Lo script, per funzionare correttamente, deve avere il permesso di esecuzione.
# Questo anche nel caso in cui venga invocato con il comando "sh".
# Spiegate perché.

Esempio 33-9. Un (utile) script che richiama sé stesso ricorsivamente

#!/bin/bash
# pb.sh: phone book

# Scritto da Rick Boivie e usato con il consenso dell'autore.
# Modifiche effettuate dall'autore de Guida ASB.

MINARG=1      #  Lo script ha bisogno di almeno un argomento.
FILEDATI=./phonebook
              #  Deve esistere un file dati di nome "phonebook"
              #+ nella directory di lavoro corrente.
NOMEPROG=$0
E_NON_ARG=70  #  Errore di nessun argomento.

if [ $# -lt $MINARG ]; then
      echo "Utilizzo: "$NOMEPROG" filedati"
      exit $E_NON_ARG
fi


if [ $# -eq $MINARG ]; then
      grep $1 "$FILEDATI"
      # 'grep' visualizza un messaggio d'errore se $FILEDATI non esiste.
else
      ( shift; "$NOMEPROG" $* ) | grep $1
      # Lo script richiama sé stesso ricorsivamente.
fi

exit 0        #  Lo script termina qui.
              #  Quindi, è corretto mettere
              #+ dati e commenti senza il # oltre questo punto.

# -------------------------------------------------------------------------
# Un estratto del file dati "phonebook":

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

#  Quando vengono passati più argomenti allo script,
#+ viene visualizzata *solo* la/e riga/he contenente tutti gli argomenti.

Esempio 33-10. Un altro (utile) script che richiama sé stesso ricorsivamente

#!/bin/bash
# usrmnt.sh, scritto da Anthony Richardson
# Utilizzato con il permesso dell'autore.

# utilizzo:    usrmnt.sh
# descrizione: monta un dispositivo, l'utente cho lo invoca deve essere elencato
#              nel gruppo MNTUSERS nel file /etc/sudoers.

# --------------------------------------------------------------------
#  Si tratta dello script usermount che riesegue se stesso usando sudo.
#  Un utente con i permessi appropriati deve digitare semplicemente

#   usermount /dev/fd0 /mnt/floppy

# invece di

#   sudo usermount /dev/fd0 /mnt/floppy

#  Utilizzo questa tecnica per tutti gli
#+ script sudo perché la trovo conveniente.
# --------------------------------------------------------------------

#  Se la variabile SUDO_COMMAND non è impostata, significa che non lo si
#+ sta eseguendo attraverso sudo, che quindi va richiamato. Vengono passati
#+ i veri id utente e di gruppo . . .

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

# Verrà eseguita questa riga solo se lo si sta eseguendo con sudo.
/bin/mount $* -o uid=$mntusr,gid=$grpusr

exit 0

# Note aggiuntive (dell'autore dello script):
# -------------------------------------------------

# 1) Linux consente l'uso dell'opzione "users" nel file /etc/fstab,
#    quindi qualsiasi utente può montare un certo dispositivo.
#    Ma, su un server, è preferibile consentire l'accesso ai dispositivi
#    solo a pochi individui.
#    Trovo che usare sudo dia un maggior controllo.

# 2) Trovo anche che, per ottenere questo risultato, sudo sia più
#    conveniente che utilizzare i gruppi.

# 3) Questo metodo fornisce, a tutti coloro dotati dei corretti permessi,
#    l'accesso root al comando mount, quindi fate attenzione a chi lo
#    concedete.
#    È possibile ottenere un controllo ancora più preciso
#    utilizzando questa tecnica in differenti script ciascono inerente a
#    mntfloppy, mntcdrom e mntsamba.

Attenzione

Troppi livelli di ricorsività possono esaurire lo spazio di stack dello script, provocando un segmentation fault.