36. Divers

Personne ne connaît vraiment la grammaire du Bourne Shell. L'examen même du code source n'apporte que peu d'information.

-- Tom Duff

36.1. Shells et scripts interactifs et non interactifs

Un shell interactif lit les commandes à partir de l'entrée utilisateur sur un terminal tty. Entre autres choses, un tel script lit les fichiers de démarrage lors de l'activation, affiche une invite et active un contrôle de job par défaut. L'utilisateur peut interagir avec le shell.

Un shell exécutant un script est toujours un shell non interactif. Tout de même, le script peut toujours accéder au tty. Il est même possible d'émuler un shell interactif dans un script.

#!/bin/bash
MON_INVITE='$ '
while :
do
  echo -n "$MON_INVITE"
  read ligne
  eval "$ligne"
  done

exit 0

# Ce script d'exemple et la plupart des explications ci-dessus sont apportés
# par Stéphane Chazelas (encore merci).

Considérons un script interactif qui demande une saisie de l'utilisateur, en général avec les fonctions read (voir l'Exemple 15.3, « Affectation d'une variable, en utilisant read »). Dans la « vraie vie », c'est un peu moins simple. À partir de maintenant, nous supposerons que notre script interactif est lié à un terminal tty, script appelé par un utilisateur à partir d'une console ou d'un terminal X.

Des scripts d'initialisation et de démarrage sont nécessairement non interactifs car ils doivent fonctionner sans intervention humaine. Beaucoup de scripts administratifs et de maintenance système sont aussi non interactifs. Les tâches répétitives invariables nécessitent une automatisation par des scripts non interactifs.

Les scripts non interactifs peuvent fonctionner en arrière-plan alors que les interactifs sont suspendus attendant une saisie qui ne viendra jamais. Gérez cette difficulté en utilisant un script expect ou une entrée intégrée de type document intégré vers un script interactif fonctionnant comme une tâche de fond. Dans le cas le plus simple, redirigez un fichier pour apporter l'entrée à la fonction read (read variable <fichier). Ces détournements particuliers rendent possible l'utilisation de scripts à usage général tournant en mode soit interactif soit non interactif.

Si un script a besoin de tester si, oui ou non, il est exécuté de manière interactive, il suffit simplement de savoir si la variable de l'invite, $PS1, est configurée (si le script attend une saisie de l'utilisateur, alors il a besoin d'afficher une invite).

if [ -z $PS1 ] # pas d'invite ?
### if [ -v PS1 ]   # Avec Bash 4.2+...
then
  # non interactif
  ...
else
  # interactif
  ...
fi

Une autre possibilité est de tester la présence de l'option « i » dans le drapeau $-.

case $- in
*i*)    # shell interactif
;;
*)      # shell non interactif
;;
# (Reproduit avec l'aimable autorisation de "UNIX F.A.Q.", 1993)
           

Cependant, John Lange décrit une méthode alternative, utilisant l'opérateur de test -t.

# Test d'un terminal !

fd=0   # stdin

#  Souvenons-nous que l'option de test -t vérifie si l'entrée
#+ standard, [ -t 0 ], ou la sortie standard, [ -t 1 ], d'un script
#+ donné de trouve dans un terminal.
if [ -t "$fd" ]
then
  echo interactif
else
  echo non interactif
fi

#  Mais comme le remarque John :
#+ si [ -t 0 ] fonctionne ... cela veut dire qu'on est introduit
#+ localement sur le système mais la commande échoue si on l'invoque à
#+ distance, à travers SSH.
#+ Par conséquent, pour un test vraiment efficace il faut également
#+ rechercher une socket.

if [[ -t "$fd" || -p /dev/stdin ]]
then
  echo interactif
else
  echo non interactif
fi
             
[Note]

Note

On peut forcer un script à fonctionner en mode interactif avec l'option -i ou avec l'en-tête #!/bin/bash -i. Faites attention au fait que ceci peut entraîner un comportement étrange du script ou afficher des messages d'erreurs même si aucune erreur n'est présente.