16.5. Commandes pour les fichiers et l'archivage

Archivage

tar

L'utilitaire standard d'archivage sous UNIX. [73] À l'origine, il s'agissait d'un programme d'archivage sur cassette (Tape ARchiving) mais il est devenu un paquet plus généraliste qui peut gérer toutes les façons d'archiver sur tout type de support, allant des lecteurs de bande aux fichiers standards, voire même sur stdout (voir l'Exemple 3.4, « Sauvegarde de tous les fichiers modifiés depuis 24 heures »). La version GNU de tar a été améliorée pour accepter différents filtres de compression tels que tar czvf archive_name.tar.gz *, qui, récursivement, archive et compresse (gzip) tous les fichiers d'un répertoire sauf ceux commençant par un point dans le répertoire courant ($PWD). [74]

Quelques options utiles de tar :

  1. -c crée (une nouvelle archive)

  2. -x extrait (les fichiers d'une archive existante)

  3. --delete supprime (les fichiers d'une archive existante)

    [Attention]

    Attention

    Cette option ne fonctionnera pas sur les périphériques à bandes magnétiques.

  4. -r ajoute (des fichiers à une archive existante)

  5. -A ajoute (des fichiers tar à une archive existante)

  6. -t liste (le contenu d'une archive existante)

  7. -u met à jour une archive

  8. -d compare une archive avec un système de fichiers spécifié

  9. --after-date traite seulement les fichiers dont la date est située chronologiquement après la date spécifiée

  10. -z compresse l'archive avec gzip

    (compresse ou décompresse suivant que cette option est combinée avec l'option -c ou -x)

  11. -j bzip2 l'archive (NdT : autre format de compression)

[Attention]

Attention

Il pourrait être difficile de récupérer des données d'une archive tar corrompue compressée avec gzip. Lors de l'archivage de fichiers importants, faites plusieurs copies.

shar

Utilitaire d'archivage shell. Dans une archive shell, les fichiers texte sont concaténés sans compression et l'archive qui en résulte est essentiellement un script shell complet, avec l'en-tête #!/bin/sh, contenant toutes les commandes nécessaires pour déballer l'archive ainsi que les fichiers eux-mêmes. Des archives shar sont toujours visibles sur les groupes de nouvelles Usenet, mais en dehors de ce cas, shar a été remplacée par tar/gzip. La commande unshar déballe les archives shar.

La commande mailshar est un script Bash script basé sur shar qui concatène plusieurs fichiers en un seul pour la messagerie électronique. Ce script prend en charge la compression et l'uuencoding.

ar

Utilitaire de création et de manipulation d'archives, principalement utilisé pour des bibliothèques de fichiers binaires.

rpm

Le gestionnaire de paquetages Red Hat (Red Hat Package Manager, ou rpm) apporte une sur-couche pour les archives source ou binaire. Il inclut des commandes pour installer et vérifier l'intégrité des paquetages, en plus d'autres choses.

Un simple rpm -i nom_paquetage.rpm suffit généralement à installer un paquetage, bien qu'il y ait bien plus d'options disponibles.

[Astuce]

Astuce

rpm -qf identifie le paquetage dont provient un fichier.

bash$ rpm -qf /bin/ls
coreutils-5.2.1-31
              
[Astuce]

Astuce

rpm -qa donne une liste complète de tous les paquetages rpm installés sur un système donné. Un rpm -qa nom_paquetage liste seulement le(s) paquetage(s) correspondant à nom_paquetage.

bash$ rpm -qa
redhat-logos-1.1.3-1
glibc-2.2.4-13
cracklib-2.7-12
dosfstools-2.7-1
gdbm-1.8.0-10
ksymoops-2.4.1-1
mktemp-1.5-11
perl-5.6.0-17
reiserfs-utils-3.x.0j-2
...


bash$ rpm -qa docbook-utils
docbook-utils-0.6.9-2


bash$ rpm -qa docbook | grep docbook
docbook-dtd31-sgml-1.0-10
docbook-style-dsssl-1.64-3
docbook-dtd30-sgml-1.0-10
docbook-dtd40-sgml-1.0-11
docbook-utils-pdf-0.6.9-2
docbook-dtd41-sgml-1.0-10
docbook-utils-0.6.9-2
              
cpio

Cette commande d'archivage spécifique à la copie (copy input and output, c'est-à-dire copie l'entrée et la sortie) est rarement utilisé car elle a été supplanté par tar/gzip. Elle a toujours son utilité, comme lors du déplacement d'un répertoire complet. Avec une taille de bloc appropriée (pour la copie), elle peut être beaucoup plus rapide que tar.

Exemple 16.30. Utiliser cpio pour déplacer un répertoire complet

#!/bin/bash

# Copier un répertoire complet en utilisant cpio.

# Avantages de l'utilisation de 'cpio' :
#   Rapidité de la copie. Il est plus rapide que 'tar' avec des tubes.
#   Convient bien pour copier des fichiers spéciaux (tubes nommés, etc.)
#+  sur lesquels 'cp' pourrait avoir du mal.

ARGS=2
E_MAUVAISARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` source destination"
  exit $E_MAUVAISARGS
fi  

source=$1
destination=$2

##############################################################################
find "$source" -depth | cpio -admvp "$destination"
#
#  Lire les pages man de find et cpio pour "décrypter" ces options.
#  La commande ci-dessus fonctionne seulement en relatif par rapport à $PWD
#+ (le répertoire courant)... des chemins complets sont indiqués.

# Exercice :
# ----------

#  Ajoutez du code pour vérifier le code de sortie ($?) du tube 'find | cpio'
#+ et affichez les messages d'erreur appropriés si quelque chose se passe mal.
##############################################################################

exit $?

rpm2cpio

Cette commande crée une archive cpio à partir d'un rpm.

Exemple 16.31. Déballer une archive rpm

#!/bin/bash
# de-rpm.sh : Déballe une archive 'rpm'

: ${1?"Usage: `basename $0` fichier_cible"}
# Doit spécifier le nom de l'archive 'rpm' comme argument.


FICHIERTEMP=$$.cpio                      # Fichier temporaire avec un nom "unique".
                                         # $$ est l'identifiant du processus du script.

rpm2cpio < $1 > $FICHIERTEMP                # Convertir l'archive rpm archive
                                            # en archive cpio.
cpio --make-directories -F $FICHIERTEMP -i  # Déballe l'archive cpio.
rm -f $FICHIERTEMP                          # Supprime l'archive cpio.

exit 0

#  Exercice :
#  Ajouter une vérification pour
#    1) s'assurer que le "fichier-cible" existe bien et
#+   2) que c'est une archive rpm.
#  Astuce :                    Analysez la sortie de la commande 'file'.

pax

La boîte à outils pax (portable archive exchange) facilite les sauvegardes périodiques de fichiers. Il est conçu pour être compatible avec toutes les déclinaisons d'UNIX, et pour remplacer tar et cpio.

pax -wf sauvegarde_quotidienne.pax ~/serveur-gnu-linux/fichiers
# Crée une archive tar de tous les fichiers du répertoire cible.
# Remarque : les options passées à pax doivent être dans le bon ordre --
#+ pax -fw     a un effet totalement différent.

pax -f sauvegarde_quotidienne.pax
# Liste les fichiers de l'archive

pax -rf sauvegarde_quotidienne.pax ~/serveur-bsd/fichiers
# Restaure les fichiers sauvegardés depuis la machine Linux
#+ vers une machine BSD.

Remarque : pax manipule plusieurs des commandes d'archivage et de compression les plus courantes.

Compression

gzip

L'utilitaire de compression standard GNU/UNIX, remplaçant compress, inférieur et propriétaire. La commande de décompression correspondante est gunzip, qui est l'équivalent de gzip -d.

[Note]

Note

L'option -c envoit la sortie de gzip sur stdout. C'est utile pour envoyer la sortie via un tube à d'autres commandes.

Le filtre zcat décompresse un fichier gzip vers stdout, comme possible entrée à une redirection ou un tube. En fait, ceci est une commande cat fonctionnant sur des fichiers compressés (incluant les fichiers créés par l'ancien utilitaire compress). La commande zcat est l'équivalent de gzip -dc.

[Attention]

Attention

Sur certains systèmes UNIX commerciaux, zcat est un synonyme pour uncompress -c, et ne fonctionnera pas avec les fichiers compressés avec gzip.

Voir aussi l'Exemple 7.7, « zmore ».

bzip2

Un autre utilitaire de compression, généralement plus efficace (mais plus lent) que gzip, spécialement sur de gros fichiers. La commande de décompression correspondante est bunzip2.

De même que la commande zcat, bzcat décompresse un fichier bzipped2-é vers la stdout.

[Note]

Note

Les nouvelles versions de tar ont acquis le support de bzip2.

compress, uncompress

C'est un utilitaire de compression plus ancien, propriétaire disponible dans les distributions UNIX commerciales. gzip, plus efficace, l'a largement remplacé. Les distributions Linux incluent généralement un compress pour des raisons de compatibilité, bien que gunzip peut déballer des fichiers traités avec compress.

[Astuce]

Astuce

La commande znew transforme les fichiers compressés en fichiers gzip.

sq

Encore un autre utilitaire de compression (squeeze), un filtre qui fonctionne seulement sur les listes de mots ASCII triées. Il utilise la syntaxe standard d'appel pour un filtre, sq < fichier-entrée > fichier-sortie. Rapide, mais loin d'être aussi efficace que gzip. Le filtre de décompression correspondant est unsq, qui s'appelle de la même manière que sq.

[Astuce]

Astuce

La sortie de sq peut être envoyé via un tube à gzip pour une meilleure compression.

zip, unzip

Utilitaire inter-plateforme d'archivage et de compression de fichiers compatible avec DOS pkzip.exe. Les archives « Zip » semblent être un medium plus ordinaire pour l'échange de fichiers sur Internet que les « archives tar ».

unarc, unarj, unrar

Ces utilitaires Linux permettent de déballer des archives compressées avec les programmes DOS arc.exe, arj.exe et rar.exe.

lzma, unlzma, lzcat

Compression Lempel-Ziv-Markov très efficace. La syntaxe de lzma est similaire à celui de gzip. Le site web 7-zip a plus d'informations.

Informations sur les fichiers

file

Un utilitaire pour identifier le type des fichiers. La commande file nom-fichier renverra une spécification du fichier nom-fichier, telle que ascii text ou data. Il utilise les numéros magiques trouvés dans /usr/share/magic, /etc/magic ou /usr/lib/magic suivant la distribution Linux/UNIX.

L'option -f fait que file tourne en mode batch, pour lire à partir d'un fichier désigné une liste de noms de fichiers à analyser. L'option -z, lorsqu'elle est utilisé sur un fichier compressé, essaie d'analyser le type du fichier décompressé.

bash$ file test.tar.gz
test.tar.gz: gzip compressed data, deflated,
last modified: Sun Sep 16 13:34:51 2001, os: UNIX

bash file -z test.tar.gz
test.tar.gz: GNU tar archive (gzip compressed data, deflated,
last modified: Sun Sep 16 13:34:51 2001, os: UNIX)
              
#  Trouve les scripts sh et Bash dans un
#+ répertoire donné :

REPERTOIRE=/usr/local/bin
MOTCLE=Bourne
# Scripts shell Bourne et Bourne-Again

file $REPERTOIRE/* | fgrep $MOTCLE

# Sortie :

# /usr/local/bin/burn-cd:          Bourne-Again shell script text executable
# /usr/local/bin/burnit:           Bourne-Again shell script text executable
# /usr/local/bin/cassette.sh:      Bourne shell script text executable
# /usr/local/bin/copy-cd:          Bourne-Again shell script text executable
# . . .

Exemple 16.32. Supprimer les commentaires des programmes C

#!/bin/bash
# strip-comment.sh : Supprime les commentaires (/* COMMENT */) d'un progamme C.

E_SANSARGS=0
E_ERREURARG=66
E_MAUVAIS_TYPE_FICHIER=67

if [ $# -eq "$E_SANSARGS" ]
then
  echo "Usage: `basename $0` fichier-C" >&2 # Message d'erreur vers stderr.
  exit $E_ERREURARG
fi  

# Test du type de fichier.
type=`file $1 | awk '{ print $2, $3, $4, $5 }'`
# "file $1" affiche le type du fichier...
# Puis awk supprime le premier champ correspondant au nom du fichier...
# Enfin, le résultat remplit la variable "type".
type_correct="ASCII C program text"

if [ "$type" != "$type_correct" ]
then
  echo
  echo "Ce script fonctionne uniquement sur les fichiers C."
  echo
  exit $E_MAUVAIS_TYPE_FICHIER
fi  


# Script sed assez complexe:
#--------
sed '
/^\/\*/d
/.*\*\//d
' $1
#--------
#  Facile à comprendre si vous prenez quelques heures pour apprendre les
#+ concepts de sed.


#  Il est possible d'ajouter une ligne supplémentaire au script sed pour gérer
#+ le cas où la ligne de code a un commentaire le suivant, sur la même ligne.
#  Ceci est laissé en exercice (difficile).

#  De même, le code ci-dessus supprime les lignes, sans commentaires, avec un
#+ "*/" ou "/*", ce qui n'est pas un effet désirable.

exit 0


# --------------------------------------------------------------------
# Le code ci-dessous ne s'exécutera pas à cause du 'exit 0' ci-dessus.

# Stephane Chazelas suggère l'alternative suivante :

usage() {
  echo "Usage: `basename $0` fichier-C" >&2
  exit 1
}

BIZARRE=`echo -n -e '\377'`   # ou BIZARRE=$'\377'
[[ $# -eq 1 ]] || usage
case `file "$1"` in
  *"C program text"*) sed -e "s%/\*%${BIZARRE}%g;s%\*/%${BIZARRE}%g" "$1" \
     | tr '\377\n' '\n\377' \
     | sed -ne 'p;n' \
     | tr -d '\n' | tr '\377' '\n';;
  *) usage;;
esac

#  Ceci ne fonctionne pas avec, par exemple :
#+ printf("/*");
#+ ou
#+ /*  /* commentaire intégré bogué */
#
#  Pour gérer tous les cas spécifiques (commentaires dans des chaînes,
#+ commentaires dans des chaînes où se trouve un \", \\" ...) la seule façon est
#+ d'écrire un analyseur C (lex ou yacc peut-être ?).

exit 0

which

which commande donne le chemin complet vers « commande ». C'est utile pour trouver si une commande ou un utilitaire particulier est installé sur le système.

$bash which rm

/usr/bin/rm

Pour une utilisation intéressante de cette commande, voir Exemple 36.14, « Un jeu de « courses de chevaux » ».

whereis

Similaire à which, ci-dessus, whereis commande donne le chemin complet vers « commande », mais aussi sa page man.

$bash whereis rm

rm: /bin/rm /usr/share/man/man1/rm.1.bz2
whatis

whatis commande recherche « commande » dans la base de données whatis. C'est utile pour identifier les commandes système et les fichiers de configuration importants. Considérez-le en tant que commande man simplifiée.

$bash whatis whatis

whatis               (1)  - search the whatis database for complete words

Exemple 16.33. Explorer /usr/X11R6/bin

#!/bin/bash

# Que sont tous ces mystérieux binaires dans /usr/X11R6/bin ?

REPERTOIRE="/usr/X11R6/bin"
# Essayez aussi "/bin", "/usr/bin", "/usr/local/bin", etc.

for fichier in $REPERTOIRE/*
do
  whatis `basename $fichier`   # affiche des informations sur le binaire.
done

exit 0
# Vous pouvez souhaiter rediriger la sortie de ce script, de cette façon :
# ./what.sh >>whatis.db
# ou la visualiser une page à la fois sur stdout,
# ./what.sh | less

Voir aussi l'Exemple 11.3, « Fileinfo : opérer sur une liste de fichiers contenue dans une variable ».

vdir

Affiche une liste détaillée du contenu du répertoire. L'effet est similaire à ls -lb.

Il fait partie de GNU fileutils.

bash$ vdir
total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo

bash ls -l
total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo
              
locate, slocate

La commande locate cherche les fichiers en utilisant une base de données enregistrée pour ce seul but. La commande slocate est la version sécurisée de locate (qui pourrait être un alias de slocate).

$bash locate hickson

/usr/lib/xephem/catalogs/hickson.edb
getfacl, setfacl

Ces commandes affichent ou assignent la liste des contrôles d'accès au fichier (en anglais file access control list) : propriétaire, groupe et droits d'accès.

bash$ getfacl *
              # fichier : test1.txt
              # propriétaire : bozo
              # groupe : bozgrp
              user::rw-
              group::rw-
              other::r--
              
              # fichier : test2.txt
              # propriétaire : bozo
              # groupe : bozgrp
              user::rw-
              group::rw-
              other::r--
 
              bash$ setfacl -m u:bozo:rw budget_annuel.csv
              bash$ getfacl budget_annuel.csv
              # fichier : budget_annuel.csv
              # propriétaire : comptable
              # groupe : grbudget
              user::rw-
              user:bozo:rw-
              user:comptable:rw-
              group::rw-
              mask::rw-
              other::r--
              
readlink

Révèle le fichier sur lequel pointe un lien symbolique.

bash$ readlink /usr/bin/awk
../../bin/gawk
              
strings

Utiliser la commande strings pour trouver les chaînes de caractères affichables dans un fichier binaire ou de données. Elle listera les séquences de caractères affichables trouvées dans le fichier cible. C'est intéressant pour un examen rapide (et sale) d'un core dump ou pour regarder un fichier image inconnu (strings fichier-image | more pourrait afficher quelque chose comme JFIF, qui identifierait le fichier en tant que graphique jpeg). Dans un script, vous devriez probablement analyser la sortie de strings avec grep ou sed. Voir l'Exemple 11.7, « Un équivalent de grep pour les fichiers binaires » et l'Exemple 11.9, « Rechercher les auteurs de tous les binaires d'un répertoire ».

Exemple 16.34. Une commande strings « améliorée »

#!/bin/bash
# wstrings.sh: "word-strings" (commande "strings" améliorée)
#
#  Ce script filtre la sortie de "strings" en la comparant avec une liste de
#+ mots communs.
#  Ceci élimine efficacement le bruit et n'affiche que les mots reconnus.

# =================================================================
#               Vérification standard des arguments du script
ARGS=1
E_MAUVAISARGS=65
E_AUCUNFICHIER=66

if [ $# -ne $ARGS ]
then
  echo "Usage: `basename $0` nomfichier"
  exit $E_MAUVAISARGS
fi

if [ ! -f "$1" ]                        # Vérifie si le fichier existe.
then
    echo "Le fichier \"$1\" n'existe pas."
    exit $E_AUCUNFICHIER
fi
# =================================================================


LONGUEUR_CHAINE_MINIMUM=3                 #  Longueur minimum d'une chaîne.
FICHIER_MOTS=/usr/share/dict/linux.words  #  Dictionnaire.
                                          #  Vous pouvez spécifier un autre
                                          #+ fichier de mots, à condition que
                                          #+ son format soit d'un mot par ligne.


listemots=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`

# Traduit la sortie de la commande 'strings' avec de multiples passes de 'tr'.
#  "tr A-Z a-z" réalise une conversion en minuscule.
#  "tr '[:space:]'" change les espaces blancs par des Z.
#  "tr -cs '[:alpha:]' Z" change les caractères non alphabétiques en Z.
#+ et ne conserve qu'un seul Z pour les Z successifs.
#  "tr -s '\173-\377' Z" convertit tous les caractères après 'z' en Z
#+ et ne conserve qu'un seul Z pour les Z successifs
#+ ce qui supprime tous les caractères bizarres que la précédente passe aurait
#+ oublié de gérer.
#  Finalement, "tr Z ' '" convertit tous les Z en espaces blancs,
#+ ce qui sera vu comme des mots séparés dans la boucle ci-dessous.

# ***************************************************************************
#  Notez la technique de remplissage de la sortie de 'tr' vers lui-même,
#+ mais avec différents arguments et/ou options à chaque passe.
# ***************************************************************************


for mot in $listemots    # Important :
                         # $listemots ne doit pas être entre guillemets ici.
                         # "$listemots" ne fonctionne pas.
                         # Pourquoi pas ?
do

  longueur_chaine=${#mot}                     # Longueur de la chaîne.
  if [ "$longueur_chaine" -lt "$LONGUEUR_CHAINE_MINIMUM" ]
  then                   # Ne pas tenir compte des petites chaînes.
    continue
  fi

  grep -Fw $mot "$FICHIER_MOTS"       # Correspond seulement aux mots complets.
#       ^^^                           #  Options "chaînes corrigées" et
                                      #+ "mots complets".

done  


exit $?

Comparaison

diff, patch

diff : utilitaire de comparaison de fichiers flexible. Il compare les fichiers cibles ligne par ligne, séquentiellement. Dans certaines applications, telles que la comparaison de dictionnaires de mots, il peut être utile pour filtrer les fichiers avec sort et uniq avant de les envoyer via un tube à diff. diff fichier-1 fichier-2 affiche en sortie les lignes qui différent des deux fichiers, avec des symboles indiquant à quel fichier appartient la ligne en question.

L'option --side-by-side de diff affiche en sortie chaque fichier comparé, ligne par ligne, dans des colonnes séparées, et avec les lignes ne correspondant pas marquées. Les options -c et -u rendent la sortie de la commande plus facile à interpréter.

Il existe de nombreuses interfaces agréables pour diff, comme sdiff, wdiff, xdiff et mgdiff.

[Astuce]

Astuce

La commande diff renvoie un état de sortie 0 si les fichiers comparés sont identiques et 1 s'ils ne le sont pas. Cela permet d'utiliser diff dans une construction de test à l'intérieur d'un script shell (voir ci-dessous).

Une utilisation commune de diff est de générer des fichiers de différences à utiliser avec patch. L'option -e permet la génération de tels fichiers, à utiliser avec des scripts ed ou ex.

patch : utilitaire de gestion de versions. Suivant un fichier de différences généré par diff, patch peut mettre à jour une version précédente d'un paquetage en une nouvelle version. Il est bien plus convenable de distribuer un fichier « diff » sensiblement plus petit que le corps entier du paquetage revu. Les correctifs (« patchs ») du noyau sont devenus la méthode préférée pour distribuer les mises à jour fréquentes du noyau Linux.

patch -p1 <correctif
# Prend toutes les modifications indiquées dans 'correctif'
# et les applique aux fichiers référencés dans le correctif.
# Ceci met à jour le paquetage en une nouvelle version.

Appliquer un correctif au noyau :

cd /usr/src
gzip -cd patchXX.gz | patch -p0
# Mettre à jour le source du noyau en utilisant 'patch'.
# De la documentation du noyau Linux, "README",
# par un auteur anonyme (Alan Cox ?).
[Note]

Note

La commande diff peut aussi comparer récursivement les répertoires (et les fichiers qui s'y trouvent).

bash$ diff -r ~/notes1 ~/notes2
Only in /home/bozo/notes1: fichier02
Only in /home/bozo/notes1: fichier03
Only in /home/bozo/notes2: fichier04
              
[Astuce]

Astuce

Utiliser zdiff pour comparer des fichiers compressés avec gzip.

[Astuce]

Astuce

Utiliser diffstat pour créer un histogramme (graphe en distribution points) en sortie de diff.

diff3, merge

Une version étendue de diff qui compare trois fichiers en une fois. Cette commande renvoie un état de sortie de si l'exécution est réussie mais, malheureusement, cela ne donne aucune information sur le résultat de la comparaison.

bash$ diff3 fichier-1 fichier-2 fichier-3
====
 1:1c
   Ceci est la ligne 1 de "fichier-1"
 2:1c
   Ceci est la ligne 1 de "fichier-2"
 3:1c
   Ceci est la ligne 1 de "fichier-3"
              

La commande merge (fusion de fichiers à 3) constitue un ajout intéressant à diff3. La syntaxe est la suivante : merge FichierInter fichier1 fichier2. Cette commande écrit sur FichierInter les différences qui mènent de fichier1 vers fichier2. On peut la voir comme une version épurée de patch.

sdiff

Compare et/ou édite les deux fichiers pour les assembler dans un fichier de sortie. Dû à sa nature interactive, cette commande trouvera peu d'utilité dans un script.

cmp

La commande cmp est une version simplifiée de diff, ci-dessus. Alors que diff reporte les différences entre deux fichiers, cmp montre simplement à quel point ils diffèrent.

[Note]

Note

Comme diff, cmp renvoie un état de sortie de 0 si les fichiers comparés sont identiques et de 1 s'ils diffèrent. Ceci permet une utilisation dans une construction de test à l'intérieur d'un script shell.

Exemple 16.35. Utiliser cmp pour comparer deux fichiers à l'intérieur d'un script.

#!/bin/bash

ARGS=2  # Deux arguments attendus par le script.
E_MAUVAISARGS=65
E_ILLISIBLE=66

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` fichier1 fichier2"
  exit $E_MAUVAISARGS
fi

if [[ ! -r "$1" || ! -r "$2" ]]
then
  echo "Les deux fichiers à comparer doivent exister et être lisibles."
  exit $E_ILLISIBLE
fi

cmp $1 $2 &> /dev/null  # /dev/null enterre la sortie de la commande "cmp".
#   cmp -s $1 $2  a le même résultat ("-s" option de silence pour "cmp")
#   Merci à Anders Gustavsson pour nous l'avoir indiqué.
#
# Fonctionne aussi avec 'diff', c'est-à-dire   diff $1 $2 &> /dev/null

if [ $? -eq 0 ]         # Test du code de sortie de la commande "cmp".
then
  echo "Le fichier \"$1\" est identique au fichier \"$2\"."
else  
  echo "Le fichier \"$1\" diffère du fichier \"$2\"."
fi

exit 0

[Astuce]

Astuce

Utiliser zcmp sur des fichiers gzippés.

comm

Utilitaire de comparaison de fichiers souple. Les fichiers doivent être triés pour qu'il soit utile.

comm -options premier-fichier second-fichier

comm fichier-1 fichier-2 affiche trois colonnes :

  • colonne 1 = lignes uniques à fichier-1

  • colonne 2 = lignes uniques à fichier-2

  • colonne 3 = lignes communes aux deux.

Les options permettent la sortie d'une ou plusieurs colonnes.

  • -1 supprime la colonne 1

  • -2 supprime la colonne 2

  • -3 supprime la colonne 3

  • -12 supprime les deux colonnes 1 et 2, etc.

Cette commande est utile pour comparer des « dictionnaires » ou des listes de mots -- fichiers texte triés avec un mot par ligne.

Utilitaires

basename

Supprime le chemin d'un nom de fichier en affichant seulement le nom. La construction basename $0 permet au script de connaître son nom, c'est-à-dire le nom par lequel il a été invoqué. Ceci peut être utilisé pour les messages d'« usage » si, par exemple, un script est appelé sans ses arguments :

echo "Usage: `basename $0` arg1 arg2 ... argn"
dirname

Supprime le basename d'un nom de fichier en n'affichant que le chemin.

[Note]

Note

basename et dirname peuvent s'exécuter sur des chaînes de caractères arbitraires. L'argument n'a pas besoin de faire référence à un fichier existant, voire même un fichier (voir l'Exemple A.7, « days-between : Calculer le nombre de jours entre deux dates »).

Exemple 16.36. basename et dirname

#!/bin/bash

a=/home/bozo/daily-journal.txt

echo "Nom de base       de /home/bozo/daily-journal.txt = `basename $a`"
echo "Nom du répertoire de /home/bozo/daily-journal.txt = `dirname $a`"
echo
echo "Mon répertoire personnel est `basename ~/`."
  # `basename ~` fonctionne aussi.
echo "Le chemin de mon répertoire personnel est `dirname ~/`."
  # `dirname ~` fonctionne aussi.

exit 0

split, csplit

Utilitaires pour diviser un fichier en plusieurs petites parties. Ils sont habituellement utilisés pour diviser un gros fichier en fichiers tenant sur une disquette ou pour préparer un courrier électronique ou pour les télécharger.

La commande csplit divise un fichier suivant le contexte, la division se faisant lorsqu'il y a correspondance de modèles.

Exemple 16.37. Un script qui se copie lui-même en sections

#!/bin/bash
# splitcopy.sh

#  A script that splits itself into chunks,
#+ then reassembles the chunks into an exact copy
#+ of the original script.

CHUNKSIZE=4    #  Size of first chunk of split files.
OUTPREFIX=xx   #  csplit prefixes, by default,
               #+ files with "xx" ...

csplit "$0" "$CHUNKSIZE"

# Some comment lines for padding . . .
# Line 15
# Line 16
# Line 17
# Line 18
# Line 19
# Line 20

cat "$OUTPREFIX"* > "$0.copy"  # Concatenate the chunks.
rm "$OUTPREFIX"*               # Get rid of the chunks.

exit $?

Codage et chiffrement

sum, cksum, md5sum, sha1sum

Ces utilitaires ont pour but de vérifier une somme de contrôle. Une somme de contrôle est un nombre [75] calculé à partir du contenu d'un fichier, dans le but de vérifier son intégrité. Un script peut se référer à une liste de sommes de contrôle pour des raisons de sécurité, comme pour s'assurer que des fichiers clés du système n'ont pas été modifié ou corrompu. Pour les applications de sécurité, utilisez la commande md5sum (message digest 5 checksum) ou, encore mieux, le nouveau sha1sum (Secure Hash Algorithm).

bash$ cksum /boot/vmlinuz
1670054224 804083 /boot/vmlinuz

bash$ echo -n "Top Secret" | cksum
3391003827 10



bash$ md5sum /boot/vmlinuz
0f43eccea8f09e0a0b2b5cf1dcf333ba  /boot/vmlinuz

bash$ echo -n "Top Secret" | md5sum
8babc97a6f62a4649716f4df8d61728f  -
              

Notez que cksum affiche aussi la taille, en octet, du fichier cible.

[Note]

Note

La commande cksum affiche la taille de sa cible en octets, qu'elle soit un fichier ou stdout.

Les commandes md5sum et sha1sum affiche un tiret lorsqu'ils reçoivent leur entrée à partir de stdout.

Exemple 16.38. Vérifier l'intégrité d'un fichier

#!/bin/bash
# file-integrity.sh : Vérifie si les fichiers d'un répertoire donné ont été
#                    modifié.

E_REP_INEXISTANT=70
E_MAUVAIS_FICHIER_BD=71

fichierdb=File_record.md5
# Fichier pour stocker les enregistrements (fichier de base de données).


init_base_donnees ()
{
  echo ""$repertoire"" > "$fichierdb"
  # Écrit le nom du répertoire sur la première ligne du fichier.
  md5sum "$repertoire"/* >> "$fichierdb"
  # Ajoute les sommes de contrôle md5 et les noms de fichiers.
}

verifie_base_donnees ()
{
  local n=0
  local nomfichier
  local somme_controle

  # ------------------------------------------------- #
  #  Cette vérification du fichier devrait être
  #+ inutile mais il est préférable de le faire.

  if [ ! -r "$fichierdb" ]
  then
          echo "Incapable de lire les somme de contrôle du fichier de base de données!"
    exit $E_MAUVAIS_FICHIER_BD
  fi
  # ------------------------------------------------- #

  while read enregistrement[n]
  do

    repertoire_verifie="${enregistrement[0]}"
    if [ "$repertoire_verifie" != "$repertoire" ]
    then
      echo "Les répertoires ne correspondent pas !"
      # Essayez d'utiliser un fichier d'un autre répertoire.
      exit $E_REP_INEXISTANT
    fi

    if [ "$n" -gt 0 ]   # Pas de nom de répertoire.
    then
      nomfichier[n]=$( echo ${enregistrement[$n]} | awk '{ print $2 }' )
      #  md5sum écrit les enregistrements après,
      #+ effectue en premier un contrôle des sommes, puis du fichier.
      somme_controle[n]=$( md5sum "${nomfichier[n]}" )


      if [ "${enregistrement[n]}" = "${somme_controle[n]}" ]
      then
        echo "${nomfichier[n]} non modifié."
        
      elif [ "`basename ${nomfichier[n]}`" != "$dbfile" ]
      #  Saute le fichier de base de données des sommes de contrôle.
      #+ car il changera à chaque appel du script.
      #  ---
      #  Ceci signifie malheureusement que lors du lancement de ce script sur
      #+ $PWD, travailler sur le fichier de base de données des sommes de
      #+ contrôle ne sera pas détecté.
      #  Exercice : Corrigez ceci.
        then
        echo "${nomfichier[n]} : ERREUR DE SOMME DE CONTRÔLE !"
        # Le fichier a été changé depuis la dernière vérification.
      fi

    fi  


    let "n+=1"
  done <"$fichierdb"       #  Lit les sommes de contrôle à partir du fichier de
                           #+ base de données.

}  

# =================================================== #
# main ()

if [ -z  "$1" ]
then
  repertoire="$PWD"     #  Si non spécifié,
else                    #+ utilise le répertoire courant.
  repertoire="$1"
fi  

clear                   # Efface l'écran.
echo " Lancement de la vérification de l'intégrité du fichier sur $repertoire"
echo

# ------------------------------------------------------------------ #
if [ ! -r "$fichierdb" ] # Besoin de créer un fichier de base de données?
  then
          echo "Configuration de la base de données, \
            \""$repertoire"/"$fichierdb"\"."; echo
    init_base_donnees
  fi  
# ------------------------------------------------------------------ #

verifie_base_donnees          # Fait le vrai travail.

echo 

#  Vous pouvez souhaiter rediriger stdout vers un fichier spécialement si le
#+ répertoire vérifié a de nombreux fichiers.

exit 0

#  Pour une explication sur la vérificaton d'intégrité,
#+ considérez le paquetage
#+ http://sourceforge.net/projects/tripwire/.

Voir aussi l'Exemple A.19, « Informations sur les répertoires », l'Exemple 36.14, « Un jeu de « courses de chevaux » » et Exemple 10.2, « Générer « de manière aléatoire » une chaîne de huit caractères » pour des utilisations créatives de la commande md5sum.

[Note]

Note

Des rapports ont indiqué que la commande md5sum 128 bits n'est plus sûre, donc sha1sum 160-bit, plus sûre, est un nouvel ajout bienvenu dans les outils de calcul de vérification.

bash$ md5sum fichiertest
e181e2c8720c60522c4c4c981108e367  fichiertest


bash$ sha1sum fichiertest
5d7425a9c08a66c3177f1e31286fa40986ffc996  fichiertest
              

Les consultants en sécurité ont démontré que même sha1sum peut être compromis. Heureusement, les dernières distributions Linux incluent des commandes dont la longueur de la clé est bien plus importante : sha224sum, sha256sum, sha384sum et sha512sum.

uuencode

Cet utilitaire encode des fichiers binaires (images, fichiers son, fichiers compressés, ...) en caractères ASCII, leur permettant d'être transmis dans le corps d'un message email ou sur un groupe de nouvelles. C'est particulièrement utile quand le codage MIME (multimédia) n'est pas disponible.

uudecode

Ceci inverse le codage, décode des fichiers passés par uuencode et récupère les binaires originaux.

Exemple 16.39. Décoder des fichier codés avec uudecode

#!/bin/bash
#  Utilise uudecode sur tous les fichiers codés avec uuencode
#+ pour le répertoire actuel.

lignes=35        # Permet 35 lignes pour l'entête (très généreux).

for Fichier in *   # Teste tous les fichiers dans $PWD.
do
  recherche1=`head -n $lignes $Fichier | grep begin | wc -w`
  recherche2=`tail -n $lignes $Fichier | grep end | wc -w`
  #  Les fichiers uuencodés ont un "begin" près du début et un "end" près de
  #+ la fin.
  if [ "$recherche1" -gt 0 ]
  then
    if [ "$recherche2" -gt 0 ]
    then
      echo "uudecoding - $Fichier -"
      uudecode $Fichier
    fi  
  fi
done  

#  Notez que lancer ce script sur lui-même le trompe et croie qu'il est un
#+ fichier uuencodé, parce qu'il contient les mots "begin" et "end".

# Exercice:
#  Modifier ce script pour vérifier si le fichier contient un en-tête de news
#+ et pour passer au fichier suivant s'il n'en trouve pas.
exit 0

[Astuce]

Astuce

La commande fold -s est utile (parfois dans un tube) pour décoder de longs messages téléchargés à partir des groupes de nouvelles Usenet.

mimencode, mmencode

Les commandes mimencode et mmencode s'occupent du codage des pièces-jointes des courriers éléctroniques. Bien que les clients mail (MUA tels que pine ou kmail) gèrent normalement ceci automatiquement, ces utilitaires particuliers permettent de manipuler de telles pièces-jointes manuellement à partir de la ligne de commande ou dans un script shell.

crypt

Pendant quelque temps, cette commande fut l'utilitaire de chiffrement standard sous UNIX. [76] Des décisions gouvernementales, motivées par les raisons politiques, ont interdit l'exportation des logiciels de chiffrement (NDLR aux États-Unis d'Amérique), avec pour conséquence la disparition de la commande crypt d'une grande partie du monde UNIX, comprenant la plupart des distributions Linux actuelles. Heureusement, des programmeurs ont mis sur pied un certain nombre de remplaçants, parmi lesquels le programme cruft (voir l'Exemple A.4, « encryptedpw : Charger un fichier sur un site ftp, en utilisant un mot de passe chiffré en local »), par l'auteur.

openssl

Il s'agit de l'implémentation libre du chiffrement Secure Sockets Layer.

# Pour encrypter un fichier :
openssl aes-128-ecb -salt -in fichier.txt -out fichier.crypte \
-pass pass:mon_mot_de_passe
#          ^^^^^^^^^^^^^^^^   Mot de passe choisi par l'utilisateur.
#       aes-128-ecb      est la méthode de chiffrement choisie.

# Pour décrypter un fichier chiffré avec openssl :
openssl aes-128-ecb -d -salt -in fichier.chiffre -out fichier.txt \
-pass pass:mon_mot_de_passe
#          ^^^^^^^^^^^^^^^^   Mot de passe choisi par l'utilisateur.

Enchaîner openssl à/depuis tar permet de chiffrer une toute arborescence de répertoires.

# Pour chiffrer un répertoire :

repsource="/home/bozo/fichiersdetest"
fichencr="rep-chiffre.tar.gz"
motdepasse=mon_mdp_secret

tar czvf - "$repsource" |
openssl des3 -salt -out "$fichencr" -pass pass:"$password"
#       ^^^^   Utilise le chiffrement des3.
# Dépose le fichier encrypté "rep-chiffre.tar.gz" dans le répertoire courant.

# Pour déchiffrer ensuite l'archive :
openssl des3 -d -salt -in "$fichencr" -pass pass:"$motdepasse" |
tar -xzv
# Déchiffre et déballe dans le répertoire courant.

Évidemment, openssl a beaucoup d'autres usages, comme la possibilité d'obtenir des certificats signés pour les sites Web. Voyez cette par d'information.

shred

Supprime un fichier de façon sûre par multiple écrasement à l'aide de suites de bits aléatoires, avant la suppression finale. Cette commande fonctionne commme Exemple 16.60, « Effacer les fichiers de façon sûre », mais d'une manière plus complète et plus élégante.

Cette commande fait partie des fileutils de GNU.

[Attention]

Attention

Des techniques post-mortem de haut niveau peuvent malgré tout permettre retrouver le contenu d'un fichier, même après le passage de shred.

Divers

mktemp

Crée un fichier temporaire [77] avec un nom de fichier « unique ». Appelé à partir de la ligne de commandes sans arguments, il crée un fichier de longueur nulle dans le répertoire /tmp.

bash$ mktemp
/tmp/tmp.zzsvql3154
              
PREFIXE=nom_fichier
fichier_temporaire=`mktemp $PREFIXE.XXXXXX`
#                          ^^^^^^ A besoin d'au moins six emplacements
#+                                dans le modèle de nom de fichier.
#   Si aucun modèle de nom n'est fourni,
#+ "tmp.XXXXXXXXXX" est la valeur par défaut.
echo "nom de fichier_temporaire = $fichier_temporaire"
# nom fichier_temporaire = nom_fichier.QA2ZpY
#                 ou quelque chose de similaire...

#  Crée un fichier de ce nom dans le répertoire courant avec les droits 600.
#  Un "umask 177" est, du coup, inutile
#  mais c'est néanmoins une bonne pratique de programmation.
make

Utilitaire pour construire et compiler des paquetages binaires. Il peut aussi être utilisé pour tout type d'opérations déclenchées par une modification de fichiers source.

La commande make vérifie le Makefile, une liste de dépendances de fichiers et les opérations à réaliser.

L'outil make est, dans l'effet, un langage de scripts puissant, similaire de nombreuses façons à Bash, mais avec la capacité de reconnaître des dépendances. Pour une explication complète de cet outil puissant, voir le site de documentation de GNU software.

install

Commande spéciale pour copier les fichiers, semblable à cp, capable de modifier les droits et les attributs des fichiers copiés. Cette commande semble faite uniquement pour l'installation de paquetages et, en tant que telle, elle fait souvent son apparition dans les Makefiles (dans la section make install :). Elle peut de la même façon trouver une utilité dans les scripts d'installation.

dos2unix

Cet utilitaire, écrit par Benjamin Lin et ses collaborateurs, convertit des fichiers texte au format DOS (lignes terminées par CR-LF) vers le format UNIX (lignes terminées uniquement par LF), et vice-versa.

ptx

La commande ptx [fichier_cible] affiche en sortie un index permuté (liste référencée) du fichier cible. Elle peut être encore filtrée et formatée dans un tube, si nécessaire.

more, less

Programmes qui affichent un fichier texte ou un flux sur stdout, un écran à la fois. Ils peuvent être utilisés pour filtrer la sortie de stdout... ou d'un script.

Une application intéressante de more est de « tester » une séquence de commandes pour en prévenir les conséquences potentiellement déplaisantes.

ls /home/bozo | awk '{print "rm -rf " $1}' | more
#                                            ^^^^

# Teste les effets de la (désastreuse) ligne de commande suivante :
#      ls /home/bozo | awk '{print "rm -rf " $1}' | sh
#      Au shell de l'exécuter...                    ^^

C'est le programme d'affichage page par page less qui est chargé de l'affichage formaté des sources des pages de manuel. Voir Exemple A.39, « Éditeur de man page ».



[73] Une archive est tout simplement un ensemble de fichiers liés stockés en un même emplacement.

[74] Un tar czvf NomArchive.tar.gz * prend en compte les fichiers commençant par un point des sous-répertoires du répertoire courant. Il s'agit d'une « fonctionnalité » non documentée de GNU tar.

[75] La somme de contrôle peut être exprimé en hexadecimal ou dans une autre base.

[76] C'est un système de chiffrement symétrique de bloc, employé pour crypter des fichiers sur un système isolé un réseau local, par opposition avec les algorithmes de chiffrement à clé publique, dont pgp est un exemple bien connu.

[77] Crée un répertoire temporaire en étant appelé avec l'option -d.