3. Caractères spéciaux

Qu'est-ce qui rend un caractère spécial ? S'il a une signification en dehors de la signification littérale, une meta signification, alors nous lui donnons le nom de caractère spécial.

Caractères spéciaux se trouvant dans les scripts et ailleurs

#

Commentaires. Les lignes commençant avec un # (à l'exception de #!) sont des commentaires et ne seront pas exécutées.

# Cette ligne est un commentaire.

Les commentaires peuvent apparaître après la fin d'une commande.

echo "Un commentaire va suivre." # Un commentaire ici.
#                               ^ Notez l'espace blanc devant #

Les commentaires peuvent aussi suivre un blanc au début d'une ligne.

        # Une tabulation précède ce commentaire.
[Attention]

Attention

Un commentaire ne peut pas être suivi d'une commande sur la même ligne. Il n'existe pas de façon de terminer le commentaire pour que le « vrai code » commence sur la même ligne. Utilisez une nouvelle ligne pour la commande suivante.

[Note]

Note

Bien sûr, un guillemet ou un # échappé dans une instruction echo ne commence pas un commentaire. De la même manière, un # apparaît dans certaines constructions de substitution de paramètres et dans les expressions numériques constantes.

echo "Le # ici ne commence pas un commentaire."
echo 'Le # ici ne commence pas un commentaire.'
echo Le \# ici ne commence pas un commentaire.
echo Le # ici commence un commentaire.

echo ${PATH#*:}       # Substitution de paramètres, pas un commentaire.
echo $(( 2#101011 ))  # Conversion de base, pas un commentaire.

# Merci, S.C.

Les caractères standards de guillemet et d'échappement (" ' \) échappent le #.

Certaines opérations de filtrage de motif font aussi appel au #.

;

Séparateur de commande [point-virgule]. Permet de placer deux commandes ou plus sur la même ligne.

echo bonjour; echo ici


if [ -x "$nomfichier" ]; then  # Notez que "if" et "then" doivent être séparés
                               # par un espace blanc. Pourquoi ?
  echo "Le fichier $nomfichier existe."; cp $nomfichier $nomfichier.sauve
else
  echo "Le fichier $nomfichier est introuvable."; touch $nomfichier
fi; echo "Test du fichier terminé."

Notez que le « ; » a parfois besoin d'être échappé.

;;

Fin de ligne dans une sélection par cas case [double point-virgule]. 

case "$variable" in
  abc)  echo "\$variable = abc" ;;
  xyz)  echo "\$variable = xyz" ;;
esac
.

Commande « point » [point]. Équivalent au source (voir l'Exemple 14.22, « « Inclure » un fichier de données »). C'est une commande intégrée de Bash.

.

« point », comme composant d'un nom de fichier. Lors de l'utilisation de noms de fichiers, un point au début est le préfixe d'un fichier « caché », un fichier que ls ne montre habituellement pas.

bash$ touch .fichier_caché
bash$ ls -l
total 10
-rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 donnée1.carnet_d_adresses
-rw-r--r--    1 bozo  bozo      4602 May 25 13:58 donnée1.carnet_d_adresses.bak
-rw-r--r--    1 bozo  bozo       877 Dec 17  2000 boulot.carnet_d_adresse


bash$ ls -al
total 14
drwxrwxr-x    2 bozo  bozo      1024 Aug 29 20:54 ./
drwx------   52 bozo  bozo      3072 Aug 29 20:51 ../
-rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 donnée1.carnet_d_adresses
-rw-r--r--    1 bozo  bozo      4602 May 25 13:58 donnée1.carnet_d_adresses.bak
-rw-r--r--    1 bozo  bozo       877 Dec 17  2000 boulot.carnet_d_adresse
-rw-rw-r--    1 bozo  bozo         0 Aug 29 20:54 .fichier_caché
              

En ce qui concerne les noms des répertoires, un seul point représente le répertoire courant et deux points de suite indiquent le répertoire parent.

bash$ pwd
/home/bozo/projets

bash$ cd .
bash$ pwd
/home/bozo/projets

bash$ cd ..
bash$ pwd
/home/bozo/
            

Le point apparaît souvent comme répertoire de destination d'une commande de mouvement de fichiers. Dans ce contexte, cela signifie le répertoire courant..

bash$ cp /home/bozo/travail_en_cours/débarras/* .
            

Copiez tous les fichiers du répertoire « débarras » dans $PWD.

.

Filtrage d'un caractère par le « point ». Pour le filtrage de caractères au sein d'une expression rationnelle, un « point » correspond à un seul caractère.

"

Citation partielle [guillemet double]. "CHAÎNE" empêche l'interprétation de la plupart des caractères spéciaux présents dans la CHAÎNE. Voir le Chapitre 5, Guillemets et apostrophes.

'

Citation totale [guillemet simple]. 'CHAÎNE' empêche l'interprétation de tous les caractères spéciaux présents dans la CHAÎNE. Ces guillemets sont plus puissants que "CHAÎNE". Voir aussi le Chapitre 5, Guillemets et apostrophes.

,

Opérateur virguleL'opérateur virgule [15] relie une suite d'opérations arithmétiques. Toutes sont évaluées, mais seul le résultat de la dernière est renvoyé.

let "t2 = ((a = 9, 15 / 3))"  # Initialise "a = 9" et "t2 = 15 / 3".
\

Échappement [antislash]. Un mécanisme d'échappement pour les caractères seuls.

\X échappe le caractère X. Cela a pour effet de « mettre X entre guillemets », et est équivalent à 'X'. Le \ peut être utilisé pour mettre " et ' entre guillemets, ce qui permet de les écrire sous forme littérale.

Voir le Chapitre 5, Guillemets et apostrophes pour une explication plus détaillée des caractères échappés.

/

Séparateur dans le chemin d'un fichier [barre oblique]. Sépare les composants d'un nom de fichier (comme dans /home/bozo/projets/Makefile).

C'est aussi l'opérateur arithmétique de division.

`

Substitution de commandes [guillemet inversé]. La construction `commande` rend la sortie de commande disponible pour l'affecter à une variable. Connu sous le nom de guillemets inversés.

:

Commande nul [deux-points]. Il s'agit de l'équivalent shell d'un « NOP » (no op, c'est-à-dire « pas d'opération »). Elle peut être considérée comme un synomyme pour la commande intégrée true. La commande « : » est elle-même une commande intégrée Bash et son état de sortie est true (0).

:
echo $?   # 0

Boucle sans fin :

while :
do
   operation-1
   operation-2
   ...
   operation-n
done

# Identique à :
#    while true
#    do
#      ...
#    done

Sert de bouche-trou dans un test if/then :

if condition
then :   # Ne rien faire et continuer
else
   faire_quelque_chose
fi

Sert de bouche-trou quand on attend une opération binaire, voir l'Exemple 8.2, « Utiliser des opérations arithmétiques » et les paramètres par défaut.

: ${nom_utilisateur=`whoami`}
# ${nom_utilisateur=`whoami`}   donne une erreur sans les deux-points en tout début
#                               sauf si "nom_utilisateur" est une commande, intégrée ou non...

Sert de bouche-trou quand on attend une commande dans un document en ligne. Voir l'Exemple 18.10, « Document en ligne « anonyme » ».

Évalue une suite de variables en utilisant la substitution de paramètres (comme dans l'Exemple 9.16, « Utiliser la substitution et les messages d'erreur »).

: ${HOSTNAME?} ${USER?} ${MAIL?}
#  Affiche un message d'erreur
#+ si une variable d'environnement (ou plusieurs) n'est pas initialisée.

Expansion de variable / remplacement d'une sous-chaîne.

En combinaison avec l'opérateur de redirection >, tronque un fichier à la taille zéro sans modifier ses droits. Crée le fichier s'il n'existait pas auparavant.

: > données.xxx   # Fichier "données.xxx" maintenant vide

# Même effet que cat /dev/null >données.xxx
# Néanmoins, cela ne crée pas un nouveau processus, car ":" est une commande intégrée.

Voir aussi l'Exemple 15.15, « Utiliser tail pour surveiller le journal des traces système ».

En combinaison avec l'opérateur de redirection >>, elle n'a pas d'effet sur un fichier cible déjà existant (: >> nouveau_fichier). Crée le fichier s'il n'existait pas.

[Note]

Note

Cela s'applique aux fichiers réguliers, mais pas aux tubes, aux liens symboliques et à certains fichiers spéciaux.

Peut servir à commencer une ligne de commentaire bien que ce ne soit pas recommandé. Utiliser # pour un commentaire désactive la vérification d'erreur pour le reste de la ligne, donc vous pouvez y mettre pratiquement n'importe quoi. En revanche, ce n'est pas le cas avec :.

: Ceci est un commentaire qui génère une erreur, ( if [ $x -eq 3] ).

Le « : » sert aussi de séparateur de champ, dans /etc/passwd et dans la variable $PATH.

bash$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games
!

Inverse le sens d'un test ou d'un état de sortie. L'opérateur ! inverse l'état de sortie de la commande à laquelle il est appliqué (voir l'Exemple 6.2, « Inverser une condition en utilisant ! »). Il inverse aussi la signification d'un opérateur de test. Par exemple, cela peut changer le sens d'un égal (=) en un différent ( != ). L'opérateur ! est un mot-clé Bash.

Dans un autre contexte, le ! apparaît aussi dans les références indirectes de variable.

Dans un contexte encore différent, à partir de la ligne de commande, le ! appelle le mécanisme d'historique de Bash (voir l'Annexe J, Commandes d'historique). Notez que ce mécanisme est désactivé dans les scripts.

*

Joker [astérisque]. Le caractère * sert de « joker » pour l'expansion des noms de fichiers dans le remplacement. Utilisé seul, il correspond à tous les noms de fichiers d'un répertoire donné.

bash$ echo *
abs-book.sgml add-drive.sh agram.sh alias.sh
              

L'astérisque * représente tout caractère répété plusieurs fois (ou zéro) dans une expression rationnelle.

*

Opérateur arithmétiqueDans le contexte des opérations arithmétiques, * indique la multiplication.

Le double astérisque ** indique l'opérateur exponentiel.

?

Opérateur de test. À l'intérieur de certaines expressions, le ? indique un test pour une condition.

Dans une construction entre parenthèses doubles, ? peut servir en tant qu'élément d'opérateur à trois arguments dans le style du C, ?:.

(( var0 = var1<98?9:21 ))
#                ^ ^

# if [ "$var1" -lt 98 ]
# then
#   var0=9
# else
#   var0=21
# fi

Dans une expression de substitution de paramètres, le ? teste si une variable a été initialisée.

?

Joker. Le caractère ? sert de joker pour un seul caractère dans l'expansion d'un nom de fichier dans un remplacement, et représente également un caractère dans une expression rationnelle étendue.

$

Substitution de variable (contenu d'une variable). 

var1=5
var2=23skidoo

echo $var1     # 5
echo $var2     # 23skidoo

Un $ préfixant un nom de variable donne la valeur que contient cette variable.

$

Fin de ligne. Dans une expression rationnelle, un $ signifie la fin d'une ligne de texte.

${}

Substitution de paramètres

$*, $@

Paramètres de position

$?

Variable contenant l'état de sortie. La variable $? contient l'état de sortie d'une commande, d'une fonction ou d'un script.

$$

Variable contenant l'identifiant du processus. La variable $$ contient le PID [16] du script dans lequel elle apparaît.

()

Groupe de commandes. 

(a=bonjour; echo $a)
[Important]

Important

Une liste de commandes entre parenthèses lance un sous-shell.

Les variables comprises dans ces parenthèses, à l'intérieur du sous-shell, ne sont pas visibles par le reste du script. Le processus parent, le script, ne peut pas lire les variables créées dans le processus fils, le sous-shell.

a=123
( a=321; )

echo "a = $a"   # a = 123
# "a" à l'intérieur des parenthèses agit comme une variable locale.

Initialisation de tableaux. 

Tableau=(element1 element2 element3)
{xxx, yyy, zzz, ...}

Expansion d'accolades. 

cat {fichier1,fichier2,fichier3} > fichier_combiné
# Concatène les fichiers fichier1, fichier2 et fichier3 dans fichier_combiné.


cp fichier22.{txt,sauve}
# Copie "fichier22.txt" dans "fichier22.sauve"

Une commande peut agir sur une liste de fichiers séparés par des virgules entre des accolades [17]. L'expansion de noms de fichiers (remplacement) s'applique aux fichiers contenus dans les accolades.

[Attention]

Attention

Aucune espace n'est autorisée à l'intérieur des accolades sauf si les espaces sont comprises dans des guillemets ou échappés.

echo {fichier1,fichier2}\ :{\ A," B",' C'}

fichier1 : A fichier1 : B fichier1 : C fichier2 : A fichier2 : B fichier2 : C

{a..z}

Expansion étendue d'accolades. 

echo {a..z} # a b c d e f g h i j k l m n o p q r s t u v w x y z
# Affiche les caractères entre a et z.

echo {0..3} # 0 1 2 3
# Affiche les caractères entre 0 et 3.

La construction {a..z} d'expansion étendue d'accolades est une fonctionnalité introduite dans la version 3 de Bash.

{}

Bloc de code [accolade]. Aussi connu sous le nom de groupe en ligne, cette construction crée une fonction anonyme (une fonction sans nom). Néanmoins, contrairement à une fonction standard, les variables d'un bloc de code restent visibles par le reste du script.

bash$ { local a;
a=123; }
bash: local: can only be used in a function
a=123
{ a=321; }
echo "a = $a"   # a = 321   (valeur à l'intérieur du bloc de code)

# Merci, S.C.

Le bloc de code entouré par des accolades peut utiliser la redirection d'entrées/sorties.

Exemple 3.1. Blocs de code et redirection d'entrées/sorties

#!/bin/bash
# Lit les lignes de /etc/fstab.

Fichier=/etc/fstab

{
read ligne1
read ligne2
} < $Fichier

echo "La première ligne dans $Fichier est :"
echo "$ligne1"
echo
echo "La deuxième ligne dans $Fichier est :"
echo "$ligne2"

exit 0

# Maintenant, comment analysez-vous les champs séparés de chaque ligne ?
# Astuce : utilisez awk, ou...
# ... Hans-Joerg Diers suggère d'utiliser la commande set de Bash.

Exemple 3.2. Sauver la sortie d'un bloc de code dans un fichier

#!/bin/bash
# rpm-check.sh

#  Recherche une description à partir d'un fichier rpm, et s'il peut être
#+ installé.
#  Sauvegarde la sortie dans un fichier.
#
#  Ce script illustre l'utilisation d'un bloc de code.

SUCCES=0
E_SANSARGS=65

if [ -z "$1" ]
then
        echo "Usage: `basename $0` fichier-rpm"
  exit $E_SANSARGS
fi  

{ # Début du bloc de code
  echo
  echo "Description de l'archive :"
  rpm -qpi $1       # Requête pour la description.
  echo
  echo "Contenu de l'archive :"
  rpm -qpl $1       # Requête pour la liste.
  echo
  rpm -i --test $1  # Requête pour savoir si le fichier rpm est installable.
  if [ "$?" -eq $SUCCES ]
  then
    echo "$1 est installable."
  else
    echo "$1 n'est pas installable."
  fi  
  echo # Fin du bloc de code
} > "$1.test"       # Redirige la sortie de tout le bloc vers un fichier.

echo "Les résultats du test rpm sont dans le fichier $1.test"

# Voir la page de manuel de rpm pour des explications sur les options.

exit 0

[Note]

Note

Contrairement à un groupe de commandes entre parenthèses, comme ci-dessus, un bloc de code entouré par des accolades ne sera pas lancé dans un sous-shell. [18]

{}

Emplacement pour du texte. Utilisé après xargs -i (option de replacement de chaîne). Les doubles accolades {} sont un emplacement pour du texte en sortie.

ls . | xargs -i -t cp ./{} $1
#            ^^         ^^

# Provient de l'exemple "ex42.sh" (copydir.sh).

{} \;

Chemin. Principalement utilisé dans les constructions find. Ce n'est pas une commande intégrée du shell.

[Note]

Note

Le « ; » termine l'option -exec d'une séquence de commandes find. Il a besoin d'être échappé pour que le shell ne l'interprète pas.

[ ]

Test. 

Teste l'expression entre [ ]. Notez que [ fait partie de la commande intégrée test (et en est un synonyme), ce n'est pas un lien vers la commande externe /usr/bin/test.

[[ ]]

Test. 

Teste l'expression entre [[ ]]. C'est un mot-clé du shell.

Voir les explications sur la structure [[ ... ]].

[ ]

Élément d'un tableau. 

Accolés au nom d'un tableau, les crochets indiquent l'indice d'un élément.

Tableau[1]=slot_1
echo ${Tableau[1]}
[ ]

Ensemble de caractères. 

Dans une expression rationnelle, les crochets désignent un ensemble de caractères devant servir de motif (N.d.T : cet ensemble peut être un intervalle).

(( ))

Expansion d'entiers. 

Développe et évalue une expression entière entre (( )).

Voir les explications sur la structure (( ... )).

> &> >& >> < <>

Redirection

nom_script >nom_fichier redirige la sortie de nom_script vers le fichier nom_fichier et écrase nom_fichier s'il existe déjà.

commande &>nom_fichier redirige à la fois stdout et stderr de commande vers nom_fichier.

commande >&2 redirige stdout de commande vers stderr.

nom_script >>nom_fichier ajoute la sortie de nom_script à la fin du fichier nom_fichier. Si le fichier n'existe pas déjà, il est créé.

[i]<>nom_fichier ouvre le fichier nom_fichier en lecture et écriture, et lui affecte le descripteur de fichier i. Si nom_fichier n'existe pas, il est créé.

Substitution de processus

(commande)>

<(commande)

Dans un autre contexte, les caractères < et > agissent comme des opérateurs de comparaison de chaînes de caractères.

Dans un contexte encore différent, les caractères < et > agissent comme des opérateurs de comparaison d'entiers. Voir aussi l'Exemple 15.9, « Utiliser expr ».

<<

Redirection utilisée dans un document en ligne

<<<

Redirection utilisée dans une chaîne en ligne

<, >

Comparaison ASCII

leg1=carottes
leg2=tomates

if [[ "$leg1" < "$leg2" ]]
then
  echo -n "Le fait que $leg1 précède $leg2 dans le dictionnaire "
  echo "n'a rien à voir avec mes préférences culinaires."
else
  echo "Mais quel type de dictionnaire utilisez-vous?"
fi
\<, \>

Délimitation d'un mot dans une expression rationnelle

bash$ grep '\<mot\>' fichier_texte

|

Tube. Passe la sortie (stdout) de la commande précédente à l'entrée (stdin) de la suivante ou au shell. Cette méthode permet de chaîner les commandes ensemble.

echo ls -l | sh
#  Passe la sortie de "echo ls -l" au shell
#+ avec le même résultat qu'un simple "ls -l".


cat *.lst | sort | uniq
#  Assemble et trie tous les fichiers ".lst", puis supprime les lignes
#+ dupliquées.

La sortie d'une ou plusieurs commandes peut être envoyée à un script via un tube.

#!/bin/bash
# uppercase.sh : Change l'entrée en majuscules.

tr 'a-z' 'A-Z'
#  La plage de lettres doit être entre guillemets pour empêcher que la
#+ génération des noms de fichiers ne se fasse que sur les fichiers à un
#+ caractère.

exit 0

Maintenant, envoyons par le tube la sortie de ls -l à ce script.

bash$ ls -l | ./uppercase.sh
-RW-RW-R--    1 BOZO  BOZO       109 APR  7 19:49 1.TXT
-RW-RW-R--    1 BOZO  BOZO       109 APR 14 16:48 2.TXT
-RW-R--R--    1 BOZO  BOZO       725 APR 20 20:56 FICHIER-DONNEES
              
[Note]

Note

Le canal stdout de chaque processus dans un tube doit être lu comme canal stdin par le suivant. Si ce n'est pas le cas, le flux de données va se bloquer et le tube ne se comportera pas comme il devrait.

cat fichier1 fichier2 | ls -l | sort
# La sortie à partir de "cat fichier1 fichier2" disparaît.

Un tube tourne en tant que processus fils et ne peut donc modifier les variables du script.

variable="valeur_initiale"
echo "nouvelle_valeur" | read variable
echo "variable = $variable"     # variable = valeur_initiale

Si une des commandes du tube échoue, l'exécution du tube se termine prématurément. Dans ces conditions, on a un tube cassé et on envoie un signal SIGPIPE.

>|

Force une redirection (même si l' option noclobber est activée). Ceci va forcer l'écrasement d'un fichier déjà existant.

||

Opérateur logique OUDans une structure de test , l'opérateur || a comme valeur de retour 0 (succès) si l'une des conditions est vraie.

&

Exécuter la tâche en arrière-plan. Une commande suivie par un & fonctionnera en tâche de fond.

bash$ sleep 10 &
[1] 850
[1]+  Done                    sleep 10
              

À l'intérieur d'un script, les commandes et même les boucles peuvent tourner en tâche de fond.

Exemple 3.3. Exécuter une boucle en tâche de fond

#!/bin/bash
# background-loop.sh

for i in 1 2 3 4 5 6 7 8 9 10            # Première boucle.
do
  echo -n "$i "
done & # Exécute cette boucle en tâche de fond.
       # S'exécutera quelques fois après la deuxième boucle.

echo   # Ce 'echo' ne s'affichera pas toujours.

for i in 11 12 13 14 15 16 17 18 19 20   # Deuxième boucle.
do
  echo -n "$i "
done

echo   # Ce 'echo' ne s'affichera pas toujours.

# ======================================================

# La sortie attendue de ce script :
# 1 2 3 4 5 6 7 8 9 10 
# 11 12 13 14 15 16 17 18 19 20 

# Mais, quelque fois, vous obtenez :
# 11 12 13 14 15 16 17 18 19 20 
# 1 2 3 4 5 6 7 8 9 10 bozo $
# (Le deuxième 'echo' ne s'exécute pas. Pourquoi ?)

# Occasionnellement aussi :
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# (Le premier 'echo' ne s'exécute pas. Pourquoi ?)

# Et très rarement :
# 11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20
# La boucle en avant plan s'exécute avant celle en tâche de fond.

exit 0

#  Nasimuddin Ansari suggère d'ajouter    sleep 1
#+ après le   echo -n "$i"   aux lignes 6 et 14,
#+ pour un peu d'amusement.

[Attention]

Attention

Une commande exécutée en tâche de fond à l'intérieur d'un script peut faire se suspendre l'exécution, attendant l'appui sur une touche. Heureusement, il est possible d'y remédier.

&&

Opérateur logique ETDans une structure de test, l'opérateur && renvoie 0 (succès) si et seulement si les deux conditions sont vraies.

-

Option, préfixe. Introduit les options pour les commandes ou les filtres. Sert aussi de préfixe pour un opérateur. Préfixe pour un paramètre par défaut dans la substitution de paramètres.

COMMANDE -[Option1][Option2][...]

ls -al

sort -dfu $nom_fichier

if [ $fichier1 -ot $fichier2 ]
then #         ^
  echo "Le fichier $fichier1 est plus ancien que le $fichier2."
fi

if [ "$a" -eq "$b" ]
then #    ^
  echo "$a est égal à $b."
fi

if [ "$c" -eq 24 -a "$d" -eq 47 ]
then #    ^              ^
  echo "$c vaut 24 et $d vaut 47."
fi


param2=${param1:-$DEFAULTVAL}
#               ^

--

Le tiret double -- est le préfixe des options longues pour les commandes.

sort --ignore-leading-blanks

Utilisé avec une commande interne Bash, il signifie la fin des options de cette commande spécifique.

[Astuce]

Astuce

Ceci donne un moyen simple pour supprimer les fichiers dont les noms commencent avec un tiret.

bash$ ls -l
-rw-r--r-- 1 bozo bozo 0 Nov 25 12:29 -mauvaisnom


bash$ rm -- -mauvaisnom

bash$ ls -l
total 0

Le double-tiret est aussi utilisé avec set.

set -- $variable (comme dans Exemple 14.18, « Réaffecter les paramètres de position »)

-

Redirection à partir de ou vers stdin ou stdout [tiret]. 

bash$ cat -
abc
abc

...

Ctl-D

Comme attendu, cat - lit sur stdin, dans ce cas la saisie de l'utilisateur au clavier, et envoie vers stdout. Mais, est-ce que la redirection des entrées/sorties utilisant - ont une application réelle ?

(cd /source/répertoire && tar cf - . ) | (cd /dest/répertoire && tar xpvf -)
# Déplace l'ensemble des fichiers d'un répertoire vers un autre
# [courtoisie d'Alan Cox <a.cox@swansea.ac.uk>, avec une modification mineure]

# 1) cd /source/répertoire
#    Répertoire source, où se trouvent les fichiers à déplacer.
# 2) &&
#    "liste ET": si l'opération 'cd' a fonctionné,
#    alors il exécute la commande suivante.
# 3) tar cf - .
#    L'option 'c' de la commande d'archivage 'tar' crée une nouvelle archive,
#    l'option 'f' (fichier), suivie par '-' désigne stdout comme fichier cible.
#    et place l'archive dans le répertoire courant ('.').
# 4) |
#    Tube...
# 5) ( ... )
#    Un sous-shell.
# 6) cd /dest/répertoire
#    Se déplace dans le répertoire de destination.
# 7) &&
#    "liste ET", comme ci-dessus.
# 8) tar xpvf -
#    Déballe l'archive ('x'), préserve l'appartenance
#    et les droits des fichiers ('p'),
#    puis envoie de nombreux messages vers stdout ('v'),
#    en lisant les données provenant de stdin
#    ('f' suivi par un '-').
#
#    Notez que 'x' est une commande, et 'p', 'v', 'f'
#    sont des options.
# Ouf !



# Plus élégant, mais équivalent à :
#   cd /source/répertoire
#   tar cf - . | (cd ../dest/répertoire; tar xpvf -)
#
#     A aussi le même effet :
# cp -a /source/répertoire/* /dest/répertoire
#     Ou :
# cp -a /source/répertoire/* /source/répertoire/.[^.]* /dest/répertoire
#     S'il y a des fichiers cachés dans /source/répertoire.
bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf -
#  --décompresse l'archive--  | --puis la passe à "tar"--
#  Si "tar" n'a pas intégré le correctif de support de "bunzip2",
#+ il faut procéder en deux étapes distinctes avec un tube.
#  Le but de cet exercice est de désarchiver les sources du noyau compressées
#+ avec bzip2.

Notez que dans ce contexte le signe « - » n'est pas en lui-même un opérateur Bash, mais plutôt une option reconnue par certains utilitaires UNIX qui écrivent dans stdout ou lisent dans stdin, tels que tar, cat, etc.

bash$ echo "quoiquecesoit" | cat -
quoiquecesoit 

Lorsqu'un nom de fichier est attendu, un - redirige la sortie vers stdout (vous pouvez le rencontrer avec tar cf), ou accepte une entrée de stdin, plutôt que d'un fichier. C'est une méthode pour utiliser un outil principalement destiné à manipuler des fichiers comme filtre dans un tube.

bash$ file
Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...
              

Tout seul sur la ligne de commande, file échoue avec un message d'erreur.

Ajoutez un « - » pour pouvoir vous en servir. Le shell attend alors une entrée de l'utilisateur.

bash$ file -
abc
standard input:              ASCII text



bash$ file -
#!/bin/bash
standard input:              Bourne-Again shell script text executable
              

Maintenant, la commande accepte une entrée de stdin et l'analyse.

Le « - » peut être utilisé pour envoyer stdout à d'autres commandes via un tube, ce qui permet quelques astuces comme l'ajout de lignes au début d'un fichier.

Par exemple, vous pouvez utiliser diff pour comparer un fichier avec une partie d'un autre fichier :

grep Linux fichier1 | diff fichier2 -

Finalement, un exemple réel utilisant - avec tar.

Exemple 3.4. Sauvegarde de tous les fichiers modifiés dans les dernières 24 heures

#!/bin/bash

#  Sauvegarde dans une archive tar compressée tous les fichiers
#+ du répertoire courant modifiés dans les dernières 24 heures.

FICHIERSAUVE=backup-$(date +%m-%d-%Y)
#                 Intégration de la date dans le nom du fichier de sauvegarde.
#                 Merci pour cette idée, Joshua Tschida.
archive=${1:-$FICHIERSAUVE}
#  Si aucun nom de fichier n'est spécifié sur la ligne de commande,
#+ nous utiliserons par défaut "backup-MM-JJ-AAAA.tar.gz."

tar cvf - `find . -mtime -1 -type f -print` > $archive.tar
gzip $archive.tar
echo "Répertoire $PWD sauvegardé dans un fichier archive \"$archive.tar.gz\"."


#  Stephane Chazelas indique que le code ci-dessus échouera si il existe trop
#+ de fichiers ou si un nom de fichier contient des espaces blancs.

# Il suggère les alternatives suivantes:
# -------------------------------------------------------------------
#   find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar"
#         avec la version GNU de "find".


#   find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \;
#         portable aux autres UNIX, mais plus lent.
# -------------------------------------------------------------------


exit 0

[Attention]

Attention

Les noms de fichiers commençant avec un « - » peuvent poser problème lorsqu'ils sont couplés avec l'opérateur de redirection « - ». Votre script doit détecter de tels fichiers et leur ajouter un préfixe approprié, par exemple ./-NOMFICHIER, $PWD/-NOMFICHIER, ou $NOMCHEMIN/-NOMFICHIER.

Il y aura probablement un problème si la valeur x d'une variable commence avec un -.

var="-n"
echo $var
# A le même effet qu'un "echo -n" et donc n'affiche rien.
-

Répertoire précédent. cd - revient au répertoire précédent en utilisant la variable d'environnement $OLDPWD.

[Attention]

Attention

Ne confondez pas « - » utilisé dans ce sens avec l'opérateur de redirection « - » vu précédemment. L'interprétation du « - » dépend du contexte dans lequel il apparaît.

-

Moins. Le signe moins indique l'opération arithmétique.

=

Égal. Opérateur d'affectation.

a=28
echo $a   # 28

Dans un autre contexte, le signe = est un opérateur de comparaison de chaînes de caractères.

+

Plus. Opérateur arithmétique d'addition.

Dans un autre contexte, le + est un opérateur d'expression rationnelle.

+

Option. Option pour une commande ou un filtre.

Certaines commandes, intégrées ou non, utilisent le + pour activer certaines options et le - pour les désactiver. Dans la substitution de paramètres, le + préfixe une autre valeur qu'une variable étend.

%

Modulo. Opérateur arithmétique modulo (reste d'une division entière).

let "z = 5 % 3"
echo $z  # 2

Dans un autre contexte, le % est un opérateur de reconnaissance de motifs.

~

Répertoire de l'utilisateur [tilde]. Le ~ correspond à la variable interne $HOME. ~bozo est le répertoire de l'utilisateur bozo et ls ~bozo liste son contenu. ~/ est le répertoire de l'utilisateur courant et ls ~/ liste son contenu.

bash$ echo ~bozo
/home/bozo

bash$ echo ~
/home/bozo

bash$ echo ~/
/home/bozo/

bash$ echo ~:
/home/bozo:

bash$ echo ~utilisateur-inexistant
~utilisateur-inexistant
              
~+

Répertoire courant. Correspond à la variable interne $PWD.

~-

Répertoire courant précédent. Correspond à la variable interne $OLDPWD.

=~

correspondance d'une expression rationnelleCet opérateur a été introduit avec la version 3 de Bash.

^

Début de ligne. Dans une expression rationnelle, un « ^ » correspond au début d'une ligne de texte.

Caractères de contrôle

Modifient le comportement d'un terminal ou de l'affichage d'un texte. Un caractère de contrôle est une combinaison CONTROL + touche (appuyés simultanément). Un caractère de contrôle peut aussi être écrit en notation octal ou hexadécimal, après un échappement.

Les caractères de contrôle ne sont normalement pas utiles à l'intérieur d'un script.

  • Ctl-A

    Déplace le curseur au début de la ligne de texte (sur la ligne de commande).

  • Ctrl-B

    Retour en arrière (backspace) non destructif.

  • Ctrl-C

    Termine un job en avant-plan.

  • Ctrl-D

    Se déconnecte du shell (similaire à un exit).

    C'est le caractère EOF (End Of File, fin de fichier), qui termine aussi l'entrée de stdin.

    Lors de la saisie de texte sur la console ou dans une fenêtre xterm, Ctl-D efface le caractère sous le curseur. Quand aucun caractère n'est présent, Ctl-D vous déconnecte de la session. Dans une fenêtre xterm, ceci a pour effet de fermer la fenêtre.

  • Ctl-E

    Moves cursor to end of line of text (on the command-line).

  • Ctl-F

    Moves cursor forward one character position (on the command-line).

  • Ctrl-G

    CLOCHE (bip). Sur quelques anciens terminaux comme les télétypes, ceci fera vraiment sonner une cloche. Dans un xterm, cela pourrait sonner.

  • Ctrl-H

    Supprime le caractère précédent (Backspace). Efface les caractères sur lequel le curseur passe en arrière.

    #!/bin/bash
    # Intègre Ctrl-H dans une chaîne de caractères.
    
    a="^H^H"                   # Deux Ctrl-H (backspaces)
                               # Ctrl-V Ctrl-H si vous utilisez vi/vim
    echo "abcdefg"             # abcdefg
    echo
    echo -n "abcdefg$a "       # abcd fg
    # Espace à la fin ^              ^ Deux fois backspaces.
    echo
    echo -n "abcdef$a"         # abcdef
    #  Pas d'espace à la fin          ^ Ne fait pas de backspace (pourquoi?).
                               # Les résultats pourraient ne pas être ceux attendus.
    echo; echo
    
    # Constantin Hagemeier suggère d'essayer :
    # a=$'\010\010'
    # a=$'\b\b'
    # a=$'\x08\x08'
    # mais cela ne modifie pas les résultats.
    
  • Ctrl-I

    Tabulation horizontale.

  • Ctrl-J

    Saut à la ligne (line feed). Dans un script, cela pourrait aussi s'exprimer en notation octale -- '\012' ou en notation hexadécimal -- '\x0a'.

  • Ctrl-K

    Tabulation verticale.

    Lors de la saisie de texte sur la console ou dans une fenêtre xterm, Ctl-K efface les caractères en commençant à partir du curseur jusqu'à la fin de la ligne. Within a script, Ctl-K may behave differently, as in Lee Lee Maschmeyer's example, below.

  • Ctrl-L

    Formfeed (efface l'écran du terminal). Dans un terminal, ceci a le même effet que la commande clear. Une fois envoyé à une imprimante, un Ctl-L éjecte la page de papier.

  • Ctrl-M

    Retour chariot.

    #!/bin/bash
    # Merci, Lee Maschmeyer, pour cet exemple.
    
    read -n 1 -s -p \
      $'Control-M place le curseur au début de cette ligne. Tapez sur Enter. \x0d'
                                      #  Bien sûr, '0d' est l'équivalent en
                                      #+ hexadécimal de Control-M.
    echo >&2   #  Le '-s' rend la frappe invisible, donc il est nécessaire d'aller
               #+ explicitement sur la nouvelle ligne.
    
    read -n 1 -s -p $'Control-J place le curseur sur la ligne suivante. \x0a'
               #  '0a' est l'équivalent hexadécimal de Control-J, le retour chariot.
    echo >&2
    
    ###
    
    read -n 1 -s -p $'Et Control-K\x0bva en bas.'
    echo >&2   #  Control-K est la tabulation verticale.
    
    # Un meilleur exemple de l'effet d'une tabulation verticale est :
    
    var=$'\x0aCeci est la ligne du bas\x0bCeci est la ligne du haut\x0a'
    echo "$var"
    #  Ceci fonctionne de la même façon que l'exemple ci-dessus. Néanmoins :
    echo "$var" | col
    #  Ceci fait que la fin de ligne droite est plus haute que la gauche.
    #  Ceci explique pourquoi nous avons commencé et terminé avec un retour chariot,
    #+ pour éviter un écran déséquilibré.
    
    # Comme l'explique Lee Maschmeyer :
    # --------------------------
    #  Dans le [premier exemple de tabulation verticale]... la tabulation verticale
    #+ fait que l'affichage va simplement en-dessous sans retour chariot.
    #  Ceci est vrai seulement sur les périphériques, comme la console Linux, qui ne
    #+ peuvent pas aller "en arrière".
    #  Le vrai but de VT est d'aller directement en haut, et non pas en bas.
    #  Cela peut être utilisé sur une imprimante.
    #  L'utilitaire col peut être utilisé pour émuler le vrai comportement de VT.
    
    exit 0
    
  • Ctl-N

    Supprime une ligne de texte rappelée à partir du tampon de l'historique [20] (sur la ligne de commande).

  • Ctl-O

    Lance un retour à la ligne (sur la ligne de commande).

  • Ctl-P

    Rappelle la dernière commande à partir du tampon historique (sur la ligne de commande).

  • Ctrl-Q

    Sort du mode pause du terminal (XON).

    Ceci réactive le stdin du terminal après qu'il ait été mis en pause.

  • Ctl-R

    Recherche arrière pour le texte dans le tampon historique (sur la ligne de commande).

  • Ctrl-S

    Pause du terminal (XOFF).

    Ceci gèle le stdin du terminal (utilisez Ctrl-Q pour en sortir).

  • Ctl-T

    Inverse la position du caractère sous le curseur avec celle du caractère précédent (sur la ligne de commande).

  • Ctrl-U

    Efface une ligne de l'entrée depuis le début de la ligne jusqu'à la position du curseur. Avec certains paramétrages, Ctl-U efface la ligne d'entrée entière, quelque soit la position du curseur.

  • Ctl-V

    Lors d'une saisie de texte, Ctl-V permet l'insertion de caractères de contrôle. Par exemple, les deux lignes suivantes sont équivalentes :

    echo -e '\x0a'
    echo <Ctl-V><Ctl-J>
    

    Ctl-V est utile principalement dans un éditeur de texte.

  • Ctl-W

    Lors de la saisie d'un texte dans une console ou une fenêtre xterm, Ctl-W efface les caractères en commençant à partir du curseur et en reculant jusqu'au premier espace blanc. Avec certains paramétrages, Ctl-W efface vers l'arrière jusqu'au premier caractère non alphanumérique.

  • Ctl-X

    Dans certains traitements de texte, coupe le texte surligné et le place dans le presse-papier.

  • Ctrl-Y

    Colle le texte à l'endroit où il a été supprimé (avec Ctrl-K ou Ctrl-U).

  • Ctrl-Z

    Met en pause un job en avant-plan.

    Opération de substitution dans certains traitements de texte.

    Caractère EOF (end-of-file) dans le système de fichiers MSDOS.

Espace blanc

Fonctionne comme un séparateur, séparant les commandes ou les variables. Les espaces blancs peuvent être desespaces, des tabulations, des lignes blanches ou d'une combinaison de ceux-ci. [21] Dans certains contextes, tels que les affectations de variable, les espaces blancs ne sont pas permis et sont considérés comme une erreur de syntaxe.

Les lignes blanches n'ont aucun effet sur l'action d'un script et sont donc utiles pour séparer visuellement les différentes parties.

La variable $IFS est une variable spéciale définissant pour certaines commandes le séparateur des champs en entrée. Elle a pour valeur par défaut une espace blanche.

Pour conserver les espaces blancs dans une chaîne ou dans une variable, utilisez des guillemets.



[15] Un opérateur est un agent qui exécute une opération. L'exemple habituel est l'opérateur arithmétique, + - * /. Avec Bash, il y a croisement entre les concepts d'opérateur et de mots clés.

[16] Un PID, ou identifiant de processus, est un numéro affecté à un processus en cours d'exécution. Les PID des processus sont visibles avec la commande ps.

Définition : un processus est un programme en cours d'exécution, quelque fois même appelé un job.

[17] Le shell fait l'expansion des accolades. La commande elle-même agit sur le résultat de cette expansion.

[18] Exception : un bloc de code entre accolades dans un tube peut être lancé comme sous-shell.

ls | { read ligne1; read ligne2; }
#  Erreur. Le bloc de code entre accolades tourne comme un sous-shell,
#+ donc la sortie de "ls" ne peut être passée aux variables de ce bloc.
echo "La première ligne est $ligne1; la seconde ligne est $ligne2"  # Ne fonctionnera pas.

# Merci, S.C.

[19] Même si dans les temps anciens, un philtre dénotait une potion dotée de pouvoirs de transformation magiques, un filtre UNIX transforme sa cible d'une façon identique. (Le codeur qui arrivera à réaliser un « philtre d'amour » qui fonctionne sur une machine Linux gagnera certainements accolades et honneur.)

[20] Bash stocke une liste de commandes auparavant lancées à partir de la ligne de commande dans un tampon, ou dans un espace en mémoire, pour retrouver l'historique à partir des commandes internes de l'historique.

[21] Un saut de ligne (newline) est aussi une espace blanche. Ceci explique pourquoi une ligne blanche, consistant seulement d'un saut de ligne, est considérée comme une espace blanche.