Les commandes Find et Grep

Introduction

La commande find permet de retrouver des fichiers à partir de certains critères. Quelques exemples pratiques, notamment avec des expressions régulières, elles sont trop peu utilisées mais si puissantes.

La commande grep quant à elle permet d'explorer un ou une série de fichiers d'un même répertoire à la recherche de texte satisfaisant une expression régulière donnée.

La commande find et ses options

Syntaxe de la commande find

La syntaxe est la suivante :

find répertoire critères

Les critères de recherche sont les suivants :

   
-name recherche sur le nom du fichier
-perm recherche sur les droits d'accès du fichier
-links recherche sur le nombre de liens du fichier
-user recherche sur le propriétaire du fichier
-group recherche sur le groupe auquel appartient au fichier
-type recherche sur le type (d=répertoire, c=caractère, f=fichier normal)
-size recherche sur la taille du fichier en nombre de blocs (1 bloc = 512 octets)
-atime recherche par date de dernier accès en lecture du fichier
-mtime recherche par date dernière modification du fichier
-ctime recherche par date de création du fichier

Il est possible de combiner les critères avec des opérateurs logiques :

  • critere 1 critere2 ou critere1 -a critere2 correspond au et (and) logique
  • !critere : non logique
  • \(critere1 -o critere2\) correspond au ou (or) logique

La commande find doit être utilisée avec l'option -print. Sans l'utilisation de cette option, même en cas de réussite dans la recherche, find n'affiche rien à la sortie standard.

La commande find est récursive, les répertoires et les sous répertoires sont scrutés par cette commande.

Recherche par nom de fichier

Pour chercher un fichier dont le nom contient la chaine de caractères chaine1 à partir du répertoire /usr, la syntaxe est la suivante :

find /usr -name chaine1 -print

Pour rechercher tous les fichiers se terminant par .c dans le répertoire /usr :

find /usr -name *.c -print

Recherche suivant la date de dernière modification

Pour connaître les derniers fichiers modifiés dans les x derniers jours dans l'arborescence :

find / -mtime x -print

Recherche suivant la taille

Pour connaître dans une arborescence, les fichiers dont la taille est supérieure à 1Mo (soit 2000 blocs de 512 Ko) :

find / -size 200 -print

Redirection des messages d'erreur

Les droits d'accès ne sont pas toujours autorisés pour certains répertoires, par conséquent, la commande find peut générer un grand nombre de messages d'erreur (permission denied etc...). Pour éviter ceci, il est possible de rediriger les messages d'erreur vers un fichier "poubelle" (ex /dev/null), les messages d'erreur sont alors perdus. Il est toutefois possible de sauvegarder ces erreurs dans un fichier régulier.

Exemple :

find . \( -name a.out -o -name "*.c" \) -print > /dev/null

dans cet exemple . signifie dans le répertoire courant.

Combinaison des commandes find et exec

L'option -print est une option que l'on passe à la commande find pour afficher les résultats à la sortie standard. En dehors de print, la commande exec peut être couplée à la commande find.

Lorsque la commande find est couplée à la commande exec, il est alors possible d'exécuter une commande sur les fichiers trouvés par la commande find.

Syntaxe

find repertoire critères -exec commande {}\ ;

Exemple : suppression de tous les fichiers core avec la commande rm

find . -name core -exec rm {}\ ;

Un exemple encore plus concret :

On recherche dans un répertoire et ses sous répertoires la liste des fichiers *.htm, *.html, *.inc, *.php, *.css, *.json, *.xml pour lesquels l'encodage est iso-8859-1. L'encodage est donné par la commande file et l'option -i :

find . -type f  \( -name "*.html" -o -name "*.htm" -o -name "*.json" -o -name "*.php" -o -name "*.inc" -o -name "*.x
ml" -o -name "*.css" -o -name "*.xml" \) -exec file -i {} \;  | grep -i 'iso-8859-1'
./admpmgportal/config.inc: text/x-php; charset=iso-8859-1
./admpmgportal/include/rules.inc: text/x-php; charset=iso-8859-1
./admpmgportal/include/treeview.inc: text/html; charset=iso-8859-1...

La commande find et les expressions régulières (-regex et -regextype)

L'exemple précédent n'est pas très élégant ( -o -name "*.css" -o -name "*.php... ). Les expressions régulières sont implémentées dans la commande find avec l'option -regex.

Le code devient bien plus lisible avec cette fonctionnalité

find . -regex '.*\.\(css\|htm\|html\|inc\|js\|json\|php\|xml\)' -exec file -i {} \;

Plusieurs librairies existent pour les expressions régulières (posix, GNU awk...), librairies pour lesquelles les syntaxes des expressions régulières peuvent différer.

L'option -regextype donne la librairie à utiliser pour l'expression régulière : un exemple de recherche des fichiers *.txt et *.inc avec la librairie posix-basic.

find -regextype posix-basic -regex ".*\(txt\|inc\)" -print

Les librairies et syntaxes d'expressions régulières sont nombreuses et elles ne sont pas détaillées ici, ce n'est pas l'objet de cet article.

Une petite astuce pour retrouver les librairies disponibles sur la plateforme utilisée : appeler une commande find avec une option -regextype invalide.

find .-regextype dummy
find: Unknown regular expression type `dummy'; valid types are `findutils-default', `awk', `egrep', `ed',
`emacs', `gnu-awk', `grep', `posix-awk', `posix-basic', `posix-egrep',
`posix-extended', `posix-minimal-basic', `sed'.

Pour gérer l'insensibilité à la casse dans les expressions régulières, utiliser l'option -iregex.

find -iregex ".*\.\(txt\)' -print./README.TXT

Combinaison des commandes find et xargs

Cette fois, on recherche la présence de la fonction PHP ereg_replace dans les fichiers *.php et *.inc.

find . -type f  \( -name "*.php" -o -name "*.inc" \) -print | xargs grep -ni "ereg_replace"
...
./sqlpacv2/prp_article.php5:216:    $caption = ereg_replace("\.","",_USRDIR_DOC)."/".$datadoc[1]["fichier"];
./sqlpacv2/prp_glossaire.php5:95:   $caption = ereg_replace("\.","",__USRDIR_DOC)."/".$article["fichier"];

La commande xargs exécute une commande echo/cat sur la donnée retournée par l'option print de la commande find. Ainsi la commande qui suit xargs (grep dans l'exemple ci-dessus) est exécutée sur le fichier.

La commande grep et ses options

Syntaxe de la commande grep

La syntaxe de la commande grep est la suivante :

grep -option(s) expression fichier

Les options de la commande grep sont les suivantes :

-v affiche les lignes ne contenant pas la chaine
-c compte le nombre de lignes contenant la chaine sans afficher les lignes
-n chaque ligne contenant la chaine est numérotée
-x  ligne correspondant exactement à la chaine
-l affiche le nom des fichiers qui contiennent la chaine
-i  option qui permet d'ignorer la casse

Quelques exemples :

grep static *.c
grep -n static *.c
grep -n '^int' *.c

Les résultats en sortie de la commande grep sont séparés par (:), ce qui permet de traiter rapidement ces résultats avec l'utilitaire awk.

Les expressions régulières avec grep, fgrep et egrep

L'option -E spécifie une expression régulière à donner à la commande grep.

Pour rechercher la chaîne de caractères mysql_connect et mysql_query dans des fichiers php d'un répertoire avec les numéros de ligne et sans être sensible à la casse :

grep -ni -E "mysql_connect|mysqlquery" *.php
cls_database_myisam.php5:59:    $objRessource = mysql_connect(_SGBD_SERVER,_SGBD_USER,$pwdUnCrypted);
cls_database_myisam.php5:108:   $return = mysql_query($queryString,$objRessource);
cls_database_myisam.php5:114:   $reserrors = mysql_query('select @errno as errno , @errmsg as errmsg'
cls_database_myisam.php5:341:   $resultPlan=mysql_query("EXPLAIN ".$query,$objRessource);

La commande egrep n'est ni plus ni moins que la commande grep avec l'option -E

egrep -ni "mysql_connect|mysql_query" *.php

La liste des termes de l'expression régulière est parfois longue pour une seule ligne de commande, c'est pourquoi les termes peuvent être définis dans un fichier texte et donnés à la commande grep avec l'otion -f

grep -ni -f mots.txt *.php
mots.txt
mysql_connect
mysql_query

Comme pour la commande find, la commande grep autorise l'utilisation de différentes syntaxes d'expressions régulières. L'option -E correspond aux expressions régulières étendues (ERE : Extended Regular Expressions). L'option -G bascule sur les expressions régulières basiques (BRE) et l'option -P sur les expressions régulières Perl.

Quelques exemples pratiques et couramment usités :

Recherche des lignes commençant par une étoile et un espace , le caractère ^ dans l'expression régulière signifie "commençant par" :

grep -ni -E "^ \*" *.php

Recherche des lignes finissant par un point virgule , le caractère $ dans l'expression régulière correspond à une fin de ligne :

grep -ni -E "$;" *.php