15. Filtres externes, programmes et commandes

Les commandes UNIX standards rendent les scripts shell plus polyvalents. La puissance des scripts provient du mélange de commandes systèmes et de directives shell avec des structures de programmation simples.

15.1. Commandes de base

Commandes incontournables pour le débutant

ls

La commande élémentaire de « listage » du contenu d'un répertoire. Il est très facile d'en sous-estimer la puissance. Par exemple, en utilisant -R, l'option de récursivité, ls affiche une structure de répertoire sous la forme d'une arborescence. D'autres options utiles sont -S, qui trie selon la taille du fichier, -t, qui trie selon la date de modification des fichiers, -b, qui affiche les caractères d'échappement, et -i, qui affiche les inodes des fichiers (voir l'Exemple 15.4, « Effacer un fichier par son numéro d'inode »).

[Astuce]

Astuce

La commande ls renvoie un code de sortie non nul lors d'une tentation d'obtention d'une fichier inexistant.

bash$ ls abc
ls: abc: No such file or directory


bash$ echo $?
2

Exemple 15.1. Utilisation de ls pour créer une liste de fichiers à graver sur un CDR

#!/bin/bash
# ex40.sh (burn-cd.sh)
# Script d'automatisation de gravure de CD.


VITESSE=2          # Peut être plus élevée si votre graveur en est capable.
FICHIER_IMAGE=cdimage.iso
FICHIER_CONTENU=contenu
PERIPHERIQUE=cdrom
#PERIPHERIQUE="0,0" pour les anciennes versions de cdrecord
REPERTOIRE_PAR_DEFAUT=/opt  # C'est le répertoire contenant les fichiers à graver.
                            # Assurez-vous qu'il existe bien.
                            # Exercice : ajoutez cette vérification.

# Utilise le package "cdrecord" de Joerg Schilling.
# http://www.fokus.fhg.de/usr/schilling/cdrecord.html

#  Si ce script est exécuté par un utilisateur normal, alors il pourrait être
#+ nécessaire de lancer suid sur cdrecord
#+ (chmod u+s /usr/bin/cdrecord, en tant que root).
#+ Bien sûr, ceci crée une petite faille de sécurité.

if [ -z "$1" ]
then
  REPERTOIRE_IMAGE=$REPERTOIRE_PAR_DEFAUT
  # Le répertoire par défaut, si non défini sur la ligne de commande.
else
  REPERTOIRE_IMAGE=$1
fi

# Créer un fichier "sommaire".
ls -lRF $REPERTOIRE_IMAGE > $REPERTOIRE_IMAGE/$FICHIER_CONTENU
# L'option "l" donne une "longue" liste de fichier.
# L'option "R" rend la liste récursive.
# L'option "F" marque le type des fichiers (les répertoires se voient ajouter un /
#+ final).
echo "Sommaire en cours de création."

# Créer un fichier image avant de le graver sur CD.
mkisofs -r -o $FICHIER_IMAGE $REPERTOIRE_IMAGE
echo "Image ISO9660 ($FICHIER_IMAGE) en cours de création."

# Grave le CD.
echo "Gravure du CD."
echo "Veuillez patientez."
cdrecord -v -isosize speed=$VITESSE dev=$PERIPHERIQUE $FICHIER_IMAGE

exit $?

cat, tac

cat, un acronyme de concatenate (NdT : concaténer en français), affiche le contenu d'un fichier sur stdout. Lorsqu'il est combiné avec une redirection (> ou >>), il est couramment utilisé pour concaténer des fichiers.

# Utilisation de cat
cat nom_fichier # Liste le fichier.
cat fichier.1 fichier.2 fichier.3 > fichier.123 # Combine les trois fichiers en un seul.

L'option -n de cat insère, avant chaque début de ligne, un numéro de ligne dans le(s) fichier(s) cible(s). L'option -b sert à numéroter uniquement les lignes qui ne sont pas blanches. L'option -v montre les caractères non imprimables en utilisant la notation ^. L'option -s n'affiche qu'une seule ligne blanche lors de multiples lignes blanches consécutives.

Voir aussi l'Exemple 15.28, « nl : un script d'autonumérotation. » et l'Exemple 15.24, « rot13 : rot13, cryptage ultra-faible. ».

[Note]

Note

Dans un tube, il pourrait être plus efficace de rediriger l'entrée standard (stdin) dans un fichier plutôt que d'utiliser la commande cat avec un fichier.

cat nom_fichier | tr a-z A-Z

tr a-z A-Z < nom_fichier #  Même effet mais lance un processus de moins
                         #+ et dispense aussi du tube.

tac, le contraire de cat, affiche le contenu d'un fichier en commençant par sa fin.

rev

Inverse chaque ligne d'un fichier et affiche le résultat vers stdout. Le résultat est différent d'une utilisation de tac, dans le sens où rev conserve l'ordre des lignes mais traite chacune d'elle de sa fin vers son début (image du miroir).

bash$ cat fichier1.txt
Coucou, je suis la ligne 1.
Coucou, je suis la ligne 2.


bash$ tac fichier1.txt
Coucou, je suis la ligne 2.
Coucou, je suis la ligne 1.


bash$ rev fichier1.txt
.1 engil al sius ej ,uocuoC
.2 engil al sius ej ,uocuoC 
              
cp

Il s'agit de la commande de copie de fichier. cp fichier1 fichier2 copie fichier1 dans fichier2. Il écrase fichier2 s'il existait auparavant (voir l'Exemple 15.6, « Copier les fichiers du répertoire courant vers un autre répertoire en utilisant xargs »).

[Astuce]

Astuce

Les options -a, pour l'archive (copier une arborescence entière de répertoire), -u pour la mise à jour (qui empêche l'écrasement de fichiers de même nom, -r et -R pour la récursivité sont particulièrement utiles.

cp -u rep_source/* rep_dest
#  "Synchronise" rep_dest_dir à partir de rep_source
#+  en copiant tous les nouveaux fichiers auparavant inexistants.
mv

C'est la commande de déplacement (move) de fichier. Elle est équivalente à une combinaison des commandes cp et rm. Elle peut être utilisée pour déplacer plusieurs fichiers vers un répertoire ou même pour renommer un répertoire. Pour des exemples d'utilisation dans un script, voir l'Exemple 9.20, « Renommer des extensions de fichiers : » et l'Exemple A.2, « rn : Un utilitaire simple pour renommer des fichiers ».

[Note]

Note

Lors de l'utilisation de mv dans un script non-interactif, on doit ajouter l'option -f (forcer) pour empêcher l'interaction avec l'utilisateur.

Quand un répertoire est déplacé vers un répertoire déjà existant, il devient un sous-répertoire du répertoire existant.

bash$ mv rep_source rep_cible

bash$ ls -lF rep_cible
total 1
 drwxrwxr-x    2 bozo  bozo      1024 nov 21 23:30 rep_source/
              
rm

Efface, supprime (« remove » en anglais) un ou plusieurs fichiers. L'option -f force même la suppression de fichiers en lecture seule et est utile pour ignorer toute interaction de l'utilisateur durant son exécution dans un script.

[Note]

Note

La commande rm échouera, d'elle-même, dans la suppression des fichiers commençant par un tiret. Pourquoi ? parce que rm voit un nom de fichier préfixé par un tiret d'option.

bash$ rm -mauvaisnom
rm: invalid option -- b
 Try `rm --help' for more information.

Un contournement intelligent permet de précéder le nom du fichier avec un «  --  » (l'option end-of-options).

bash$ rm -- -mauvaisnom

Une autre méthode revient à ajouter au début du nom du fichier un point et un slash.

bash$ rm ./-mauvaisnom
[Avertissement]

Avertissement

Lorsqu'elle est exécutée avec l'option de récursivité (NdT : en anglais, « recursive flag ») -r, cette commande efface les fichiers de tous les sous-répertoires de l'arborescence à partir du répertoire actuel. Lancer rm -rf * sans faire trop attention peut supprimer une grosse partie de la structure d'un répertoire.

rmdir

Efface un répertoire (« remove directory » en anglais). Il est nécessaire que le répertoire soit vide de tout fichier -- ce qui inclut les fichiers invisibles (NdT : en anglais, les dotfiles), [55] -- pour que cette commande s'exécute correctemment.

mkdir

Crée un répertoire (NdT : « make directory » en anglais). Par exemple, mkdir -p projet/programmes/Decembre crée le répertoire indiqué. L'option -p s'occupe, au besoin, de la création des répertoires parents automatiquement.

chmod

Change les attributs d'un fichier ou d'un répertoire existant (voir l'Exemple 14.13, « Forcer une déconnexion »).

chmod +x nom_fichier
# Rend "nom_fichier" exécutable pour tous les utilisateurs.

chmod u+s nom_fichier
# Active le bit de droit "suid" de "nom_fichier".
#  Un utilisateur ordinaire peut exécuter "nom_fichier" avec les mêmes
#+ droits que son propriétaire.
# (Ceci ne s'applique pas aux scripts shell.)
chmod 644 nom_fichier
#  Active les droits de lecture/écriture de "nom_fichier" pour son
#+ propriétaire et lecture seulement pour
# les autres (mode octal).

chmod 444 nom_fichier
#  Rend "nom_fichier" en lecture seule pour tous.
#  Modifier le fichier (par exemple, avec un éditeur texte)
#+ non autorisé pour un utilisateur qui ne possède par le fichier (sauf root),
#+ et même le propriétaire du fichier doit forcer une sauvegarde du fichier
#+ en cas de modification.
#  Les même restrictions s'appliquent à la suppression du fichier.</programlisting></para>
chmod 1777 nom_rep
#  Donne à tout le monde les droits de lecture, d'écriture et d'exécution
#+ dans le répertoire mais active aussi le "sticky bit".
#  Cela signifie que seul le propriétaire du répertoire, le propriétaire du
#+ fichier et, bien sûr, root peuvent effacer un fichier de ce
#+ répertoire.

chmod 111 nom_rep
#  Donne seulement le droit d'exécution à tout le monde dans un répertoire.
#  Ceci signifie que vous pouvez exécuter et lire les fichiers de ce
#+ répertoire (les droits d'exécution incluent nécessairement les droits de
#+ lecture car vous ne pouvez pas exécuter un fichier sans le lire).
#  Mais vous ne pouvez pas lister les fichiers ou les rechercher avec la
#+ commande "find".
#  Ces restrictions ne s'appliquent pas à root.

chmod 000 nom_rep
#  Aucun droit pour ce répertoire.
#  Impossible de lire, écrire ou exécuter les fichiers qui y sont contenus.
#  Impossible même d'y lister les fichiers ou de s'y déplacer.
#  Mais vous pouvez renommer (mv) le répertoire
#+ ou le supprimer (rmdir) s'il est vide.
#  Vous pouvez même créer un lien symbolique vers les fichiers de ce répertoire
#+ mais vous ne pouvez pas lire, écrire ou exécuter les liens symboliques.
#  Ces restrictions ne s'appliquent pas à root.
chattr

Change les attributs de fichier (NdT : « change file attributes » en anglais). Ceci est analogue à chmod ci-dessus mais avec des options différentes et une syntaxe d'appel différente. Cela fonctionne seulement sur un système de fichiers ext2.

Une option particulièrement intéressante de chattr est i. chattr +i filename marque le fichier comme non modifiable. Le fichier ne peut pas être modifié ou supprimé, un lien ne peut pas être établi vers lui, y compris par root. Cet attribut de fichier ne peut être initialisé ou supprimé que par root. D'une façon similaire, l'option a marque le fichier de façon à ce que les utilisateurs ne puissent qu'ajouter des informations.

root# chattr +i fichier1.txt
root# rm fichier1.txt
rm: remove write-protected regular file `file1.txt'? y
rm: cannot remove `file1.txt': Operation not permitted

Si le fichier a l'attribut s (sécurité), alors, quand il est supprimé, les blocs sont écrasés avec des zéros sur le disque.

Si le fichier a l'attribut u (non supprimable), alors, à sa suppression, son contenu pourra toujours être récupéré.

Si un fichier a l'attribut c (compression), alors il sera automatiquement compressé lors de son écriture sur le disque et décompressé lors de sa lecture.

[Note]

Note

Les attributs du fichier configurés avec chattr ne s'affichent pas dans la liste des fichiers (ls -l).

ln

Crée des liens vers des fichiers déjà existants. Un « lien » est une référence vers un fichier. La commande ln permet de référencer le fichier lié par plus d'un nom et est une alternative supérieure au système d'alias (voir l'Exemple 4.6, « wh, recherche d'un nom de domaine avec whois »).

ln crée simplement une référence, un pointeur vers le fichier pour une taille de seulement quelques octets.

La commande ln est le plus souvent utilisée avec l'option -s, option de lien symbolique ou ou lien « soft ». Les avantages de l'utilisation de l'option -s est que cela permet de faire des liens entre systèmes de fichiers ou des répertoires.

La syntaxe de la commande est un peu spéciale. ln -s ancien_fichier nouveau_fichier lie le fichier ancien_fichier au lien nouvellement créé, nouveau_fichier.

[Attention]

Attention

Si un fichier nommé nouveau_fichier existe, un message d'erreur apparaîtra.

Les liens permettent d'appeller un script (ou tout autre type d'exécutable) avec des noms multiples et de faire en sorte que ce script se comporte suivant la façon dont il a été appelé.

Exemple 15.2. Hello or Good-bye

#!/bin/bash
# hello.sh: Dire "bonjour" ou "bonsoir"
#+          suivant la façon dont le script a été appelé.

# Faire un lien dans le répertoire courant ($PWD) vers ce script :
#    ln -s bonjour.sh bonsoir
# Maintenant, essayez d'appeler le script de deux façons :
# ./bonjour.sh
# ./bonsoir


APPEL_BONJOUR=65
APPEL_BONSOIR=66

if [ $0 = "./bonsoir" ]
then
  echo "Bonsoir !"
  # Autres commandes du type au-revoir, de façon approprié.
  exit $APPEL_BONSOIR
fi

echo "Bonjour !"
# Autres commandes du type bonjour, de façon approprié.
exit $APPEL_BONJOUR

man, info

Ces commandes accèdent aux pages de manuel et d'information relatives aux commandes systèmes et autres utilitaires installés sur la machine. Les pages info, si disponibles, contiennent habituellement des descriptions bien plus détaillées que celles des pages man.



[55] Il s'agit de fichiers dont le nom commence par un point, par exemple ~/.Xdefaults. De tels noms de fichiers ne sont pas affichés lors d'un ls, et ne risquent donc pas d'être effacés accidententellement par une commande rm -rf *. Ces fichiers sont utilisés habituellement en tant que fichiers de configuration situés dans le répertoire principal d'un utilisateur.