Outils pour utilisateurs

Outils du site


commande:grep_egrep

— page corrigée — oh!rocks 2009/05/09 19:30

grep, egrep : recherche sur fichiers

Pouvoir isoler rapidement un élément dans un fichier de configuration, dans la sortie d'une commande ou dans un fichier texte quelconque est un atout essentiel sur un système GNU-Linux pour lequel “tout est fichier” (citation de Kenneth Thompson, père du système UNIX). C'est ce que proposent les commandes grep et egrep.
“egrep” était à l'origine une version étendue et améliorée de “grep”. “egrep” supporte les expressions régulières étendues. Avec “grep” l'option “-E” permet également de supporter les expressions régulières étendues. Une alternative “fgrep” existe, à l'origine plus rapide que “grep” mais ne supportant absolument pas les expressions régulières. “fgrep” ne cherchant des chaînes de caractères que de manière littérale, a donc peu d'intérêt, si ce n'est une plus grande économie de ressources sur des machines très anciennes. L'option “-F” de “grep” donne un comportement similaire, c'est d'ailleurs le comportement par défaut. Depuis 2001 la norme POSIX définie les options “-E” et “-F” comme les standards, “egrep” et “fgrep” sont officiellement démodés, mais toujours disponibles et largement utilisés.

Un signe $ précède les commandes qui ne nécessitent pas de droits administrateur ; un signe # précède celles qui nécessitent des droits administrateur (ces signes ne font PAS partie des commandes). Les lignes qui ne commencent pas par un signe $ ou # correspondent au résultat de la commande précédente.
Les touches utilisées sont indiquées entre crochets, exemple [ctrl] pour la touche “contrôle”

usages simples : recherche dans un fichier texte

Imaginons que nous voulions savoir si le système de sécurité “selinux” est compilé dans notre noyau. Nous allons chercher la chaîne de caractère “selinux” dans le fichier de configuration du noyau “/boot/config-$(uname -r)” :

$ egrep selinux /boot/config-$(uname -r)

Oups ! La commande ne renvoie rien alors que l'option “selinux” est forcément présente qu'elle soit activée ou non… Cet échec s'explique facilement : les options de configuration du noyau sont notées en majuscules. Or, “egrep” et “grep” sont sensibles à la casse. Pour obtenir le résultat il faudrait écrire “SELINUX” ou mieux, utiliser l'option “-i” qui permet d'ignorer la casse (l'expression est cherchée qu'elle soit en minuscules ou majuscules).

$ egrep -i selinux /boot/config-$(uname -r)
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
# CONFIG_SECURITY_SELINUX_DISABLE is not set
CONFIG_SECURITY_SELINUX_DEVELOP=y
CONFIG_SECURITY_SELINUX_AVC_STATS=y
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX=y
CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE=19

C'est mieux ! Mais vu que la configuration du noyau est un document conséquent, il serait intéressant d'avoir les numéros de lignes des résultats trouvés… C'est possible avec l'option “-n” :

$ egrep -in selinux /boot/config-$(uname -r)
3350:CONFIG_SECURITY_SELINUX=y
3351:CONFIG_SECURITY_SELINUX_BOOTPARAM=y
3352:CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
3353:# CONFIG_SECURITY_SELINUX_DISABLE is not set
3354:CONFIG_SECURITY_SELINUX_DEVELOP=y
3355:CONFIG_SECURITY_SELINUX_AVC_STATS=y
3356:CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
3357:CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX=y
3358:CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE=19

Maintenant, cherchons deux motifs différents dans cette même configuration pour savoir si les solutions de virtualisation “xen” et/ou “kvm” sont compilés :

$ egrep -in '(kvm|xen)' /boot/config-$(uname -r)
202:# CONFIG_XEN is not set
203:CONFIG_KVM_CLOCK=y
204:CONFIG_KVM_GUEST=y
1334:CONFIG_NETXEN_NIC=m
3465:CONFIG_HAVE_KVM=y
3467:CONFIG_KVM=m
3468:CONFIG_KVM_INTEL=m
3469:# CONFIG_KVM_AMD is not set

Les guillemets simples qui entourent l'expression évitent que le shell interprète les caractères spéciaux (les parenthèses et le “|” tube). Si vous voulez ajouter un troisième motif de recherche, ajoutez simplement un “|” (tube) et indiquez le motif :

$ egrep -in '(kvm|xen|virtio)' /boot/config-$(uname -r)
202:# CONFIG_XEN is not set
203:CONFIG_KVM_CLOCK=y
204:CONFIG_KVM_GUEST=y
878:CONFIG_VIRTIO_BLK=m
1334:CONFIG_NETXEN_NIC=m
1562:CONFIG_VIRTIO_NET=m
1753:# CONFIG_VIRTIO_CONSOLE is not set
1763:CONFIG_HW_RANDOM_VIRTIO=m
3465:CONFIG_HAVE_KVM=y
3467:CONFIG_KVM=m
3468:CONFIG_KVM_INTEL=m
3469:# CONFIG_KVM_AMD is not set
3470:CONFIG_VIRTIO=m
3471:CONFIG_VIRTIO_RING=m
3472:CONFIG_VIRTIO_PCI=m
3473:CONFIG_VIRTIO_BALLOON=m

Simple. Pour obtenir le même résultat avec “grep” il faudrait utiliser la syntaxe :

$ grep -i -e kvm -e xen -e virtio /boot/config-$(uname -r)

Ce qui est moins élégant.

Si maintenant vous voulez chercher un seul motif mais dans plusieurs fichiers, il suffit d'en indiquer les chemins à la suite, séparés par un espace :

# egrep nobody /etc/group /etc/gshadow
/etc/group:lp:x:7:nobody,tux
/etc/group:nobody:x:1002:
/etc/gshadow:nobody:!::

Si maintenant vous désirez chercher dans tous les fichiers à l'intérieur de /etc (option “-R”), le mot “staff” de manière stricte (pas de mots formés avec “staff”, option “-w”), en excluant le répertoire /etc/alternatives et tout répertoire dont le nom contient “dictionarie” (dictionnaire)(options --exclude-dir=“), le tout avec un résultat en couleurs pour en améliorer la lisibilité (option ”--colorise“ :

# egrep -Rw --color --exclude-dir=alternatives --exclude-dir=*dictionarie* staff /etc
/etc/group-:staff:x:50:
/etc/gshadow-:staff:*::
/etc/gshadow:staff:*::
/etc/group:staff:x:50:
/etc/htdig/english.0:staff/DGMRSZ
/etc/group.org:staff:x:50:

Pour chercher les lignes commençant par “net” dans le fichier /etc/sysctl.conf, utilisez le motif ^ :

$ egrep ^net /etc/sysctl.conf
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.secure_redirects = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1

Et pour les lignes finissant par “1”, utilisez le motif $:

$ egrep 1$ /etc/sysctl.conf
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
#net.ipv4.tcp_syncookies=1
#net.ipv4.ip_forward=1
#net.ipv6.conf.all.forwarding=1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.secure_redirects = 1
net.ipv4.conf.all.log_martians = 1
kernel.sysrq = 1

Voici un petit mémo des options utiles et des caractères pouvant servir à construire des motifs de recherche :

options egrep usage
-i ignorer la casse
-n indiquer le numéro de ligne
-v chercher les lignes qui n'incluent PAS le motif de recherche
-R chercher de manière récursive tous les fichiers du(des) répertoire(s)
-w ne chercher le motif QUE comme mot entier
–exclude-dir= exclure un répertoire de la recherche (utile en recherche récursive)
–color colorie le résultat pour en améliorer la lisibilité
-B n donne les “n” lignes du fichier AVANT le résultat trouvé (“egrep -B 5” donnera cinq lignes avant)
-A n donne les “n” lignes du fichier APRÈS le résultat trouvé (“egrep -A 5” donnera cinq lignes après)
-C n donne les “n” lignes de contexte AVANT ET APRÈS le motif trouvé ; deux tirets ”--“ séparent les résultats
motifs spéciaux usage
^ chercher une ligne commençant par (exemple: egrep ^net /etc/sysctl.conf)
$ chercher une ligne finissant par (exemple: egrep 1$ /etc/sysctl.conf)

"grep" et "egrep" utilisés comme filtres

Un usage très courant de “grep” et “egrep” est celui de filtre servant à sélectionner une partie du résultat d'une autre commande. Il suffit pour cela d'utiliser une redirection de la commande originale vers “grep”. L'opérateur de redirection généralement utilisé est le “tube” (“pipe” en anglais) “|”. Par exemple, voici une recherche du module uvcvideo (pilote pour webcam) dans le résultat de “lsmod” (liste les modules en fonction) :

$ lsmod | grep uvcvideo
uvcvideo               55740  0
videodev               40656  1 uvcvideo
v4l1_compat            12612  2 uvcvideo,videodev

Pour lister uniquement les répertoires sur un chemin donné (ici /etc) :

$ ls -l /etc | grep ^d

Ou pour les exclure (chercher uniquement les fichiers et liens) :

$ ls -l /etc | grep -v ^d

Le résultat de “ls -l” commence par la lettre “d” s'il s'agit d'un répertoire (“directory” en anglais) : c'est cette caractéristique qui est utilisée par “grep”. On cherche d'abord les lignes commençant par “d” (^d), puis on met une négation à cette condition dans la deuxième commande (on liste les “non-répertoires”) avec l'option ”-v“.

Si on veut isoler parmi les messages système ceux concernant l'usb, on fera :

$ dmesg | grep -i usb

Certaines commandes nécessitent des astuces. Par exemple, pour filtrer le résultat de “ps aux” en recherchant les lignes commençant par “1000” (pid de l'utilisateur courant) et sans que “grep” et “ps” n'apparaissent parmi les processus listés :

$ ps aux | egrep -vw '(ps|egrep)' | egrep 1000

On utilise la négation (-v) du motif de recherche (ps|egrep). On utilise l'option “stricte” (-w) pour éviter de masquer des processus qui contiendrait la séquence “ps”. Bien entendu, si vous aviez un script qui fonctionne en arrière-plan et qui utilise massivement “egrep”, il n'apparaîtrait pas non plus… C'est le revers de la méthode.

Une alternative astucieuse est d'utiliser systématiquement une expression régulière, même pour un motif de recherche simple :

$ ps aux | egrep [1]000

L'expression ”[1]000“ est vraie pour le chiffre “1000”, mais pas pour les caractères ”[1]“, donc “egrep” n'apparaîtra pas dans les résultats.

Pour rechercher une expression dans des fichiers OpenOffice ”.odt“ avec “find” et “grep”. Cela dépasse le cadre de l'usage de “grep”, mais cela peut s'avérer pratique et montre comment combiner la commande de recherche “find” et “grep”. On prendra l'exemple d'un répertoire /home/tux/Doc/ contenant de nombreux fichiers ”.odt“ (“Oasis Document Text”, le format de Ooo Writer). On recherchera l'expression “Saint Valentin”. Cette commande tire partie du fait que les ”.odt“ sont en réalité des fichiers zippés (compressés en ”.zip“) dont le contenu textuel est stocké dans un fichier “content.xml”:

$ find /home/tux/Doc/ -name '*.odt' -exec sh -c 'unzip -c "{}" content.xml | grep -qi "saint valentin"' ";" -print

Attention à ne pas oublier les guillemets simples et doubles qui sont indispensables pour éviter que le shell n'interprète certains caractères spéciaux.
Pour adapter à vos besoins, remplacez simplement le chemin /home/tux/Doc par votre répertoire, et “saint valentin” par l'expression que vous recherchez. L'option ”-i“ permet de s'assurer que l'expression sera trouvée même si la casse est différente (majuscules…). Le nom du fichier dans lequel l'expression a été trouvé vous sera renvoyé en cas de succès.

J'espère que vous êtes convaincus de l'utilité de “grep” et “egrep”, et surtout plus à l'aise dans leur maniement ! ;-)

Liens

commande/grep_egrep.txt · Dernière modification: 2014/05/09 18:56 (modification externe)