15.2. Commandes complexes

Commandes pour utilisateurs plus expérimentés

find

-exec COMMANDE \;

Exécute COMMANDE sur chaque fichier trouvé par find. La séquence de commandes se termine par un ; (le « ; » est échappé pour être certain que le shell le passe de façon littérale à find, sans l'interpréter comme un caractère spécial).

bash$ find ~/ -name '*.txt'
/home/bozo/.kde/share/apps/karm/karmdata.txt
/home/bozo/misc/irmeyc.txt
/home/bozo/test-scripts/1.txt
              

Si COMMAND contient {}, alors find substitue le chemin complet du fichier sélectionné à « {} ».

find ~/ -name 'core*' -exec rm {} \;
# Supprime tous les fichiers core à partir du répertoire de l'utilisateur.
find /home/bozo/projects -mtime -1
#                                               ^   Attention au signe
#+ "moins"
#  Liste tous les fichiers situés dans le répertoire /home/bozo/projects
#+ qui ont été modifiés durant les dernières 24 heures
#+ (jour_d_aujourdhui - 1).
#
find /home/bozo/projects -mtime 1
#  Comme ci-dessus, but mais modifés il y a *exactement* 24 heures.
#
#  mtime = date de dernière modification du fichier cible
#  ctime = date de dernier changement d'état (via 'chmod' ou autre)
#  atime = date du dernier accès

REP=/home/bozo/fichiers_bidons
find "$REP" -type f -atime +5 -exec rm {} \;
#                          ^           ^^
#  Les accolades sont un indicateur pour le chemin trouvé par "find."
#
#  Efface tous les fichiers contenus dans "/home/bozo/fichiers_bidons"
#+ qui n'ont pas été accédés depuis *au moins* 5 jours (signe "plus"... +5).
#
#  "-type typefichier", où
#  f = fichier classique
#  d = répertoire
#  l = lien symbolique, etc.
# 
#  (La page de manuel et la page info de 'find' ont 
#  (La liste complète des options se trouve dans la page de manuel et
#  dans la page info de 'find'.)
find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;

#  Trouve toutes les adresses IP (xxx.xxx.xxx.xxx) contenues dans les fichiers
#+ situés dans le répertoire /etc .
#  Quelques correspondances n'auront rien à voir - Peuvent-elles être
#+ éliminées ?

# Peut-être en faisant:

find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
 | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
#
#  [:digit:] est un ensemble de caractères POSIX 1003.2
#+ introduit avec le standard POSIX 1003.2.

# Merci, Stéphane Chazelas.
[Note]

Note

L'option -exec de find ne doit pas être confondue avec la commande intégrée du shell exec.

Exemple 15.3. Badname élimine dans le répertoire courant les fichiers dont le nom contient des caractères incorrects et des espaces blancs.

&ex57;

Exemple 15.4. Effacer un fichier par son numéro d'inode

&idelete;

La commande find fonctionne aussi sans l'option -exec.

#!/bin/bash
#  Trouve les fichiers suid root.
#  Un fichier suid étrange pourrait indiquer une faille de sécurité
#+ voire même une intrusion dans le système.

repertoire="/usr/sbin"
# Essayer aussi /sbin, /bin, /usr/bin, /usr/local/bin, etc.
droits="+4000"  # suid root (dangerous!)


for fichier in $( find "$repertoire" -perm "$droits" )
do
  ls -ltF --author "$fichier"
done

Voir l'Exemple 15.30, « Utiliser cpio pour déplacer un répertoire complet », l'Exemple 3.4, « Sauvegarde de tous les fichiers modifiés dans les dernières 24 heures » et l'Exemple 10.9, « Rechercher les auteurs de tous les binaires d'un répertoire » pour des exemples de scripts utilisant find. La page de manuel de cette commande, complexe et puissante, apporte des détails supplémentaires.

xargs

C'est un filtre pour passer les arguments à une commande, et aussi un outil pour assembler les commandes entre elles. xargs découpe un flux de données en morceaux suffisamment petits pour être traités par les filtres ou les commandes. On peut le considérer comme une alternative puissante aux apostrophes inverses. Dans les situations où la substitution de commande échoue avec l'erreur trop d'arguments, remplacer par xargs a de bonnes chances de régler le problème. [62] Habituellement, xargs lit depuis stdin ou depuis un tube mais il accepte aussi de lire dans la sortie d'un fichier.

La commande par défaut d'xargs est echo. Cela signifie que tout flux entrant transmis via un tube vers xargs peut voir ses sauts de ligne et caractères d'espacements supprimés.

bash$ ls -l
total 0
 -rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 fichier1
 -rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 fichier2


bash$ ls -l | xargs
total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 fichier1 -rw-rw-r-- 1 bozo bozo 0 Jan...



bash$ find ~/mail -type f | xargs grep "Linux"
./misc:User-Agent: slrn/0.9.8.1 (Linux)
 ./sent-mail-jul-2005: hosted by the Linux Documentation Project.
 ./sent-mail-jul-2005: (Linux Documentation Project Site, rtf version)
 ./sent-mail-jul-2005: Subject: Criticism of Bozo's Windows/Linux article
 ./sent-mail-jul-2005: while mentioning that the Linux ext2/ext3 filesystem
 . . .
              

ls | xargs -p -l gzip : Compresse avec gzip tous les fichiers du répertoire courant, un à un, et demande confirmation avant chaque opération.

[Note]

Note

Notez que xargs traite les arguments qui lui sont passés séquentiellement, un à la fois.

bash$ find /usr/bin | xargs file
/usr/bin:          directory
 /usr/bin/foomatic-ppd-options:          perl script text executable
 . . .
              

[Astuce]

Astuce

Une option intéressante d'xargs est -n NN, qui limite à NN le nombre d'arguments passés.

ls | xargs -n 8 echo : Affiche le contenu du répertoire courant sur 8 colonnes.

[Astuce]

Astuce

Une autre option utile est -0, combinée avec find -print0 ou grep -lZ. Ceci permet de manipuler les arguments contenant des espaces ou des quotes.

find / -type f -print0 | xargs -0 grep -liwZ GUI | xargs -0 rm -f

grep -rliwZ GUI / | xargs -0 rm -f

N'importe laquelle des commande ci-dessus effacera tout fichier contenant « GUI ». (Merci, S.C.)

Or:

cat /proc/"$pid"/"$OPTION" | xargs -0 echo
#  Formate la sortie :     ^^^^^^^^^^^^^^^
#  À partir de la correction de Han Holl sur le script "get-commandline.sh"
#+ du chapitre "/dev et /proc".

Exemple 15.5. Fichier de traces utilisant xargs pour surveiller les journaux système

&ex41;

Comme avec find, une paire d'accolades sert à indiquer un texte à remplacer.

Exemple 15.6. Copier les fichiers du répertoire courant vers un autre répertoire en utilisant xargs

&ex42;

Exemple 15.7. Tuer des processus par leur nom

&killbyname;

Exemple 15.8. Analyse de la fréquence des mots en utilisant xargs

&wf2;

expr

Le script ci-dessus illustre comment expr utilise les opérateurs groupant appelés parenthèses echappées -- \( ... \) -- en tandem avec une analyse basée sur les expressions rationnelles pour faire coïncider une sous-chaîne de caractères. Voici un autre exemple, cette fois provenant de la « vie réelle. »

# Supprimer les espaces en début et en fin.
LRFDATE=`expr "$LRFDATE" : '[[:space:]]*\(.*\)[[:space:]]*$'`

#  Provient du script "booklistgen.sh" de Peter Knowles,
#+ script convertissant des fichiers au format Librie/PRS-50X de Sony.
#  (http://booklistgensh.peterknowles.com)

Perl, sed et awk ont des capacités d'analyse de chaînes de caractères très largement supérieures. Une petite sous-routine sed ou awk dans un script (voir la Section 33.3, « Scripts d'appel ») est aussi une bonne alternative à l'utilisation d'expr.

Voir la Section 9.2, « Manipuler les chaînes de caractères » pour en savoir plus sur l'utilisation d'expr dans les manipulations des chaînes de caractères.



[62] Et même quand xargs n'est pas strictement nécessaire, il peut accélérer l'exécution d'une commande impliquant le traitement en flot de plusieurs fichiers.