Chapitre 14. Substitution de commandes
Une substitution de
commande réassigne la sortie d'une commande
ou même de multiples commandes; elle branche littéralement la
sortie d'une commande sur un autre contexte.
La forme classique de la substitution
de commande utilise l'apostrophe inverse (`...`). Les commandes placées à l'intérieur
de ces apostrophes inverses génèrent du texte en ligne de commande.
nom_du_script=`basename $0`
echo "Le nom de ce script est $nom_du_script." |
rm `cat nomfichier` # << nomfichier >> contient une liste de fichiers à effacer.
#
# S. C. fait remarquer qu'une erreur "arg list too long" (liste d'arguments trop longue)
#+ pourrait en résulter.
# Mieux est xargs rm -- < nomfichier
# ( -- couvre les cas dans lesquels << nomfichier >> commence par un
#+ << - >> )
listing_fichierstexte=`ls *.txt`
# Cette variable contient les noms de tous les fichiers *.txt dans le répertoire de
#+ travail actuel.
echo $listing_fichierstexte
listing_fichierstexte2=$(ls *.txt) # La forme alternative d'une substitution de commande.
echo $listing_fichierstexte2
# Même résultat.
# Un problème qui peut advenir lorsque l'on place une liste de fichiers dans une chaîne
#+ simple
# est qu'une nouvelle ligne peut s'y glisser.
# Une méthode plus sûre d'assigner une liste de fichiers à un paramètre est d'utiliser
#+ un tableau.
# shopt -s nullglob # S'il n'y a pas de correspondance, les noms de fichier sont
#+ transformés en chaîne vide.
# listing_fichierstextes=( *.txt )
#
# Merci, S.C. |
 | Les substitutions de commandes peuvent provoquer des coupures de mots.
COMMANDE `echo a b` # 2 arguments: a et b
COMMANDE "`echo a b`" # 1 argument : "a b"
COMMANDE `echo` # pas d'argument
COMMANDE "`echo`" # un argument vide
# Merci, S.C. |
Même s'il n'y a pas coupure de mots, une substitution de
commandes peut ôter les retours à la ligne finaux.
# cd "`pwd`" # Ceci devrait toujours fonctionner.
# Néanmoins...
mkdir 'répertoire avec un retour à la ligne final
'
cd 'répertoire avec un retour à la ligne final
'
cd "`pwd`" # Message d'erreur:
# bash: cd: /tmp/fichier avec un retour à la ligne final: Pas de tel fichier
#+ ou répertoire
cd "$PWD" # Fonctionne parfaitement.
ancien_parametrage_tty=$(stty -g) # Sauve les anciens paramètres du terminal.
echo "Appuyez sur une Touche "
stty -icanon -echo # Désactive le mode "canonique" du terminal.
# Désactive également l'écho *local* .
touche=$(dd bs=1 count=1 2> /dev/null) # Utilisation de dd pour obtenir
#+ l'appui d'une touche.
stty "$ancien_parametrage_tty" # Restaure les anciens paramètres.
echo "Vous avez appuyé sur ${#touche} touche." # ${#variable} = $variable
#
# Appuyez sur toute autre touche que RETURN, et la sortie est "Vous avez
#+ appuyé sur 1 touche"
# Appuyez sur RETURN, et c'est "Vous avez appuyé sur 0 touche."
# Le retour à la ligne a été avalé par la substitution de commande.
Merci, S.C. |
|
 | L'utilisation d'echo pour afficher la
valeur d'une variable non protégée
affectée à l'aide d'une substitution de commande retire les
caractères de nouvelle ligne finaux de la sortie des commandes
ainsi redirigées. Ce qui peut créer des surprises désagréables.
listing_rep=`ls -l`
echo $listing_rep # non protégée
# Dans l'attente de la liste bien ordonnée du contenu d'un répertoire.
# En fait, voici ce que l'on obtient:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh
# Les retours à la ligne ont disparu.
echo "$listing_rep" # protégée
# -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt
# -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh
# -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh |
|
La substitution de commande permet même d'affecter à une
variable le contenu d'un fichier, en utilisant soit une redirection soit la commande cat
variable1=`<fichier1` # Affecte à "variable1" le contenu de "fichier1".
variable2=`cat file2` # Affecte à "variable2" le contenu de "fichier2".
# Soyez conscient que ces variables peuvent alors contenir des espaces,
#+ voire même (horreur), des caractères de contrôle. |
# Extraits des fichiers système, /etc/rc.d/rc.sysinit
#+ (sur une installation Red Hat Linux)
if [ -f /fsckoptions ]; then
fsckoptions=`cat /fsckoptions`
...
fi
#
#
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
hdmedia=`cat /proc/ide/${disk[$device]}/media`
...
fi
#
#
if [ ! -n "`uname -r | grep -- "-"`" ]; then
ktag="`cat /proc/version`"
...
fi
#
#
if [ $usb = "1" ]; then
sleep 5
mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
...
fi |
 | Ne pas affecter le contenu d'un
gros fichier texte à une variable à moins que vous n'ayez une bonne raison
de le faire. Ne pas affecter le contenu d'un fichier
binaire à une variable, même pour blaguer. Exemple 14-1. Trucs de script stupides #!/bin/bash
# stupid-script-tricks.sh: Ne tentez pas ça chez vous, les gars!
# D'après "Trucs de Scripts Stupides," Volume I.
variable_dangereuse=`cat /boot/vmlinuz` # Le noyau Linux compressé en personne.
echo "longueur de la chaîne \$variable_dangereuse = ${#variable_dangereuse}"
# longueur de la chaîne $variable_dangereuse = 794151
# (Ne donne pas le même résultat que 'wc -c /boot/vmlinuz'.)
# echo "$variable_dangereuse"
# N'essayez pas de faire ça! Cela figerait le script.
# L'auteur de ce document n'a pas connaissance d'une l'utilité quelconque pour
#+ l'affectation à une variable du contenu d'un fichier binaire.
exit 0 |
Notez qu'on ne provoque pas de
surcharge de tampon.
C'est un exemple où un langage interprété, tel que Bash,
fournit plus de protection vis à vis des erreurs
de programmation qu'un langage compilé. |
Une substitution de commande permet d'affecter à une
variable la sortie d'une boucle. L'idée pour y parvenir
est de se servir de la sortie d'une commande echo placée à l'intérieur de la
boucle.
Exemple 14-2. Générer le contenu d'une variable à partir d'une boucle
#!/bin/bash
# csubloop.sh: Initialiser une variable à la sortie d'une boucle.
variable1=`for i in 1 2 3 4 5
do
echo -n "$i" # La commande 'echo' est essentielle
done` #+ à la substitution de commande.
echo "variable1 = $variable1" # variable1 = 12345
i=0
variable2=`while [ "$i" -lt 10 ]
do
echo -n "$i" # A nouveau le nécessaire 'echo'.
let "i += 1" # Incrémentation.
done`
echo "variable2 = $variable2" # variable2 = 0123456789
exit 0 |
 | La syntaxe $(COMMANDE) a remplacé
les apostrophes inverses pour la substitution de commande.
sortie=$(sed -n /"$1"/p $fichier)
# Tiré de l'exemple "grp.sh". |
|
Exemples de substitution de commandes dans des scripts shell :
Exemple 10-7
Exemple 10-26
Exemple 9-26
Exemple 12-2
Exemple 12-15
Exemple 12-12
Exemple 12-39
Exemple 10-13
Exemple 10-10
Exemple 12-24
Exemple 16-7
Exemple A-18
Exemple 28-1
Exemple 12-32
Exemple 12-33
Exemple 12-34