Aller au contenu

Les outils de recherche

Objectif : maîtriser les opérations de recherche sur un système Linux.

Un système Linux comme le serveur Oracle Linux que vous avez installé est composé de dizaines voire de centaines de milliers de fichiers et de répertoires, sans compter les données. Il arrive parfois que l'on ait à chercher un certain fichier ou un certain répertoire dans tout ce fatras. Et là, comment faire ? Naviguer manuellement dans tous les répertoires et les sous-répertoires jusqu'à ce que l'on trouve ce que l'on cherche ? Essayez donc, mais vous n'irez probablement pas bien loin. Autant chercher une aiguille dans une botte de foin, voire dans un continent de granges. Heureusement pour nous, notre système Linux comporte toute une panoplie d'outils de recherche aussi simples que puissants.

Chercher l'emplacement d'un fichier dont on connaît le nom

Partons tout de suite d'un exemple concret. Vous vous rappelez que le fichier qui contient la configuration de la boucle locale s'appelle ifcfg-lo, mais vous ne vous souvenez plus de son emplacement exact. Que faire alors ? Essayez ceci, en tant que root :

# find / -name 'ifcfg-lo'
/etc/sysconfig/network-scripts/ifcfg-lo

La commande peut se lire de la sorte :

  • "Trouve (find)...

  • ... en dessous du répertoire racine (/)...

  • ... tous les fichiers qui s'appellent ifcfg-lo (-name 'ifcfg-lo')."

Le fichier recherché se trouve dans le répertoire /etc/sysconfig/network-scripts.

Essayons avec un autre nom de fichier, au hasard tout en choisissant bien :

# find / -name '.bashrc'
/etc/skel/.bashrc
/root/.bashrc
/home/microlinux/.bashrc
/home/adebuf/.bashrc
/home/jmortreux/.bashrc

J'obtiens pas moins de cinq résultats, situés respectivement dans /etc/skel, dans /root ainsi que dans les répertoires d'utilisateur respectifs de microlinux, adebuf et jmortreux.

Limiter la recherche à certains répertoires

Admettons que j'aie une vague idée des bottes de foin dans lesquelles il faut chercher et que je veuille restreindre mon périmètre de recherche. Je pourrais sommer find d'effectuer sa recherche en dessous du répertoire /etc :

# find /etc -name '.bashrc'
/etc/skel/.bashrc

Je pourrais faire la même chose pour /home :

# find /home -name '.bashrc'
/home/microlinux/.bashrc
/home/adebuf/.bashrc
/home/jmortreux/.bashrc

Zone interdite

Pourquoi vaut-il mieux être root pour se lancer dans la recherche d'un fichier de configuration du système ? Essayez donc d'effectuer la recherche suivante en tant que simple utilisateur et voyez le résultat :

$ find /etc -name 'ifcfg-lo'
find: ‘/etc/grub.d’: Permission denied
find: ‘/etc/pki/CA/private’: Permission denied
find: ‘/etc/pki/rsyslog’: Permission denied
/etc/sysconfig/network-scripts/ifcfg-lo
find: ‘/etc/polkit-1/rules.d’: Permission denied
find: ‘/etc/polkit-1/localauthority’: Permission denied
find: ‘/etc/firewalld’: Permission denied
find: ‘/etc/selinux/targeted/active’: Permission denied
find: ‘/etc/selinux/final’: Permission denied
find: ‘/etc/dhcp’: Permission denied
find: ‘/etc/lvm/archive’: Permission denied
find: ‘/etc/lvm/backup’: Permission denied
find: ‘/etc/lvm/cache’: Permission denied
find: ‘/etc/audisp’: Permission denied
find: ‘/etc/audit’: Permission denied
find: ‘/etc/sudoers.d’: Permission denied

Songez à ce que nous avons vu dans la précédente leçon sur les droits d'accès. Certains répertoires de votre système sont à l'abri des regards curieux des simples utilisateurs, ce qui aura forcément une incidence sur le fonctionnement des outils de recherche. En l'occurrence, la commande find invoquée en tant que simple utilisateur vous servira si votre recherche porte effectivement sur le contenu de votre propre répertoire :

$ pwd
/home/microlinux
$ find . -name '.bashrc'
./.bashrc

Si la syntaxe de cette dernière commande vous laisse perplexe, rappelez-vous que le point . signifie "ici". Notez que j'aurais pu écrire aussi bien :

$ find /home/microlinux -name '.bashrc'
/home/microlinux/.bashrc

Ou encore :

$ find ~ -name '.bashrc'
/home/microlinux/.bashrc

Vous aurez remarqué que le nom du fichier recherché figure entre une paire d'apostrophes : '...'. Dans les exemples que nous venons de voir, l'utilisation des apostrophes n'est pas obligatoire, mais je vous conseille de prendre de bonnes habitudes et de les utiliser quand même. Nous verrons bientôt des cas de figure où leur omission produirait des erreurs. En revanche, vous êtes libre d'utiliser des apostrophes ' ou des guillemets ", cela n'a pas d'importance ici.

Faire fi des avertissements

Notre précédente recherche en tant que simple utilisateur nous a affiché une multitude d'avertissements relatifs aux permissions. Or, au beau milieu des accès non accordés, notre fichier ifcfg-lo a bel et bien été trouvé et affiché comme résultat de recherche valide :

$ find /etc/ -name 'ifcfg-lo'
find: ‘/etc/grub.d’: Permission denied
...
/etc/sysconfig/network-scripts/ifcfg-lo
...
find: ‘/etc/sudoers.d’: Permission denied

Une astuce consiste ici à ne pas afficher les avertissements et les erreurs, en redirigeant ceux-ci vers le vide-ordures de notre système, si l'on peut dire :

$ find /etc -name 'ifcfg-lo' 2> /dev/null
/etc/sysconfig/network-scripts/ifcfg-lo

Rien ne vous empêche d'opter ainsi pour l'équivalent numérique de la pensée positive. En revanche, gardez à l'esprit que find vous affichera uniquement les fichiers et les répertoires auxquels vous avez effectivement accès :

$ find / -name '.bashrc' 2> /dev/null
/etc/skel/.bashrc
/home/microlinux/.bashrc

La commande find présente un seul désavantage. Elle n'est pas toujours très rapide. Il peut arriver que vous souhaitiez interrompre une recherche en cours. Dans ce cas, il suffit d'appuyer sur Ctrl+C, la combinaison de touches pour interrompre un processus.

Chercher des fichiers dont on ne connaît pas le nom exact

Il arrive assez souvent d'oublier une partie du nom du fichier recherché. Dans ce cas, il vous faudra recourir aux caractères de substitution.

Par exemple, vous cherchez un fichier pour modifier la configuration de votre serveur SSH. Tout ce que vous savez, c'est que son nom commence par ssh et que le tout se situe en dessous de /etc. Dans ce cas, il suffit de saisir :

# find /etc -name 'ssh*'
/etc/pam.d/sshd
/etc/systemd/system/multi-user.target.wants/sshd.service
/etc/sysconfig/sshd
/etc/ssh
/etc/ssh/sshd_config
/etc/ssh/ssh_config
/etc/ssh/ssh_host_rsa_key
/etc/ssh/ssh_host_rsa_key.pub
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_ed25519_key.pub
/etc/selinux/targeted/active/modules/100/ssh

Si vous vous rappelez que c'est un fichier dont le nom finit par config et qui se situe en dessous de /etc/ssh, vous taperez :

# find /etc/ssh -name '*config'
/etc/ssh/sshd_config
/etc/ssh/ssh_config

Évidemment, vous pouvez combiner les jokers à votre guise.

Par ailleurs, l'option -iname rend la recherche insensible à la casse, c'est-à-dire qu'elle ignorera l'utilisation des majuscules et des minuscules dans les noms de fichiers et de répertoires :

# find /etc -iname 'readme'
/etc/grub.d/README
/etc/rc.d/init.d/README
/etc/pki/ca-trust/README
/etc/pki/ca-trust/extracted/README
/etc/pki/ca-trust/extracted/java/README
/etc/pki/ca-trust/extracted/openssl/README
/etc/pki/ca-trust/extracted/pem/README
/etc/pki/ca-trust/source/README

Chercher selon d'autres critères que le nom

Chercher en fonction de la taille

La taille d'un fichier constitue également un critère de recherche. L'exemple suivant nous affichera par ordre alphabétique tous les programmes dans /usr/bin dont la taille dépasse 500 kilo-octets :

# find /usr/bin -size +500k | sort
/usr/bin/bash
/usr/bin/dgawk
/usr/bin/dwp
/usr/bin/gpg2
...

Appliquer une commande sur les fichiers trouvés

Il se peut que vous vouliez soumettre le résultat de votre recherche à un traitement. Concrètement, imaginez que vous souhaitiez obtenir un listing plus détaillé des fichiers retournés par notre dernière recherche. Évidemment, vous pourriez très bien invoquer ls -l manuellement sur chacun des fichiers trouvés, mais ce serait un peu fastidieux. Dans ce cas, il vaut mieux utiliser l'option -exec de find :

# find /usr/bin -size +500k -exec ls -l {} \;
-rwxr-xr-x. 1 root root 964544  11 avril 02:53 /usr/bin/bash
-rwxr-xr-x. 1 root root 514168  28 juin  2017  /usr/bin/dgawk
-rwxr-xr-x. 1 root root 525272  9 juin   2014  /usr/bin/troff
-rwxr-xr-x. 1 root root 3178120 11 avril 07:38 /usr/bin/dwp
-rwxr-xr-x. 1 root root 910072  11 avril 01:54 /usr/bin/vi
...

La syntaxe de cette option vous paraîtra un peu moins biscornue si vous considérez que la paire d'accolades {} symbolise "le résultat de la recherche".

La dernière opération s'effectue plus simplement en utilisant xargs, une commande qui sert à construire et exécuter des lignes de commande à partir de l'entrée standard (d'après la page de manuel xargs(1)). Essayez :

# find /usr/bin -size +500k | xargs ls -l
-rwxr-xr-x. 1 root root  964544 11 avril 02:53 /usr/bin/bash
-rwxr-xr-x. 1 root root  514168 28 juin   2017 /usr/bin/dgawk
-rwxr-xr-x. 1 root root 3178120 11 avril 07:38 /usr/bin/dwp
-rwxr-xr-x. 1 root root  749928  5 nov.   2016 /usr/bin/gpg2
...

Chercher par type

Dans l'état actuel des choses, notre plate-forme d'entraînement manque de fichiers. Nous n'avons pas grand-chose à nous mettre sous la dent pour l'instant. Nous allons remédier à cela, en copiant par exemple tout le contenu de /etc dans notre répertoire d'utilisateur. Nous devons effectuer cette manipulation avec les droits root, faute de quoi nous aurons quelques problèmes de permissions :

# cp -R /etc /home/microlinux/

Attribuez l'ensemble de cette arborescence à votre utilisateur et redevenez ce dernier :

# chown -R microlinux:microlinux /home/microlinux/etc/
# exit

Dans cette arborescence en dessous de ~/etc, nous trouvons essentiellement deux choses :

  • des répertoires et des sous-répertoires ;

  • des fichiers.

Cherchons tous les répertoires et sous-répertoires dans cette arborescence, sans tenir compte des fichiers. C'est l'option -type de find qui nous donnera le résultat escompté :

$ find ~/etc -type d

Le résultat de cette recherche dépasse la taille d'un écran et il faut admettre qu'il n'est pas très éloquent. Essayons d'obtenir un affichage plus détaillé :

$ find ~/etc -type d | xargs ls -ld | less

Chercher selon les droits d'accès

En faisant dérouler la liste, nous constatons que les droits d'accès ne sont pas les mêmes pour tous les répertoires. Beaucoup sont en rwxr-xr-x (755), mais on trouve aussi des occurrences de rwxr-x--- (750) et de rwx------ (700).

L'option -perm permet de les isoler :

$ find ~/etc/ -type d -perm 750 | xargs ls -ld | less
...
$ find ~/etc/ -type d -perm 700 | xargs ls -ld | less
...

Cas pratique : attribuer des permissions à un ensemble de fichiers

Admettons maintenant que nous souhaitions définir des droits rwxr-xr-x pour tous les répertoires contenus dans ~/etc. Combinons le résultat de la recherche précédente avec une commande chmod :

$ find ~/etc -type d -exec chmod 0755 {} \;

Oui, je sais, on dirait que le chat a marché sur le clavier.

Réitérez la recherche de répertoires combinée avec un affichage détaillé des résultats :

$ find ~/etc -type d -exec ls -ld {} \;

Vous constatez qu'à présent tous les répertoires ont des droits d'accès rwxr-xr-x identiques.

Procédons de manière similaire pour les fichiers. Pour les trouver, il faut combiner find avec l'option -type f :

$ find ~/etc -type f -exec ls -l {} \;

Attribuons-leur à tous une permission rw-r--r-- (644) :

$ find ~/etc -type f -exec chmod 644 {} \;

Jetez un oeil rapide au résultat de la commande pour en avoir le coeur net.

Certains remarqueront que la syntaxe avec xargs paraît bien plus simple et se demanderont à juste titre pourquoi je ne l'utilise pas d'emblée. Tentez l'expérience et vous verrez que vous aurez des problèmes avec les fichiers et les répertoires dont le nom contient des espaces ou autres caractères spéciaux.

L'exemple que je viens de vous donner n'est abstrait que dans le sens où les données sur lesquelles nous l'avons appliqué sont à utilité discutable. Il existe cependant des cas de figure sur lesquels il peut s'appliquer tel quel, notamment dans l'assainissement des droits pour toutes les données importées à partir de certains périphériques de stockage de masse.

Nous verrons plus loin les différents systèmes de fichiers sous Linux. Pour l'instant, sachez que la plupart des périphériques amovibles comme les disques externes, les clés USB et autres lecteurs MP3 sont formatés avec un système de fichiers FAT32. C'est un système de fichiers rudimentaire, utilisé par les anciens systèmes Windows, mais théoriquement toujours valable. Il présente le grand avantage (le seul d'ailleurs) d'être géré aussi bien par Microsoft Windows que par macOS ou Linux. Parmi ses inconvénients (déjà plus nombreux), on trouve l'absence de gestion des permissions de fichiers. Résultat de l'affaire : lorsque vous importez des fichiers et des répertoires à partir d'un tel périphérique, vous vous retrouvez avec des rwxrwxrwx partout. Dans ce cas, une des premières choses à faire, c'est de restituer des droits d'accès un peu plus sains.

Chercher du texte à l'intérieur d'un fichier

Nous venons de voir un outil efficace et flexible pour retrouver des fichiers dans notre système, mais existe-t-il un moyen de retrouver du texte à l'intérieur de ces fichiers ? Oui et c'est là que grep entre en jeu.

grep est un filtre qui retrouve des chaînes de caractères, non seulement dans un fichier, mais aussi dans une arborescence touffue. C'est un outil de recherche puissant et sophistiqué, sur lequel il serait aisé de rédiger des chapitres aussi complexes que rébarbatifs. Au lieu de cela, nous allons nous limiter à quelques exemples pratiques utilisables au quotidien.

Pour commencer, affichez le contenu de votre fichier /etc/passwd :

$ cat /etc/passwd

Rappelez-vous que ce fichier contient des renseignements sur tous les utilisateurs du système, c'est-à-dire l'administrateur root, les utilisateurs système et les utilisateurs "réels".

Il est possible de filtrer cet affichage, pour ne visualiser que les lignes qui contiennent une certaine chaîne de caractères, en l'occurrence bash :

$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
microlinux:x:1000:1000:Microlinux:/home/microlinux:/bin/bash
adebuf:x:1001:1001:Agnès Debuf:/home/adebuf:/bin/bash
jmortreux:x:1002:1002:Jean Mortreux:/home/jmortreux:/bin/bash

Nous pouvons aussi écrire plus simplement :

$ grep bash /etc/passwd
root:x:0:0:root:/root:/bin/bash
microlinux:x:1000:1000:Microlinux:/home/microlinux:/bin/bash
adebuf:x:1001:1001:Agnès Debuf:/home/adebuf:/bin/bash
jmortreux:x:1002:1002:Jean Mortreux:/home/jmortreux:/bin/bash

Cette dernière commande signifie en français : "affiche-moi toutes les lignes du fichier /etc/passwd qui contiennent la chaîne de caractères bash."

Comme -iname pour find, l'option -i rend la recherche insensible à la casse :

$ grep -i jean /etc/passwd
jmortreux:x:1002:1002:Jean Mortreux:/home/jmortreux:/bin/bash

Cette syntaxe fonctionne pour des chaînes de caractères comme pour des mots simples. Dès que le terme recherché contient des caractères tels que des espaces, nous devons employer des guillemets :

$ grep "Agnès Debuf" /etc/passwd
adebuf:x:1001:1001:Agnès Debuf:/home/adebuf:/bin/bash

Dans certains cas, il s'avère pratique d'afficher le numéro de la ligne à laquelle se trouve la chaîne de caractères en question. C'est particulièrement utile pour les fichiers un peu plus longs et c'est l'option -n qui s'en charge :

$ grep -n "imaps" /etc/services
262:imaps    993/tcp    # IMAP over SSL
263:imaps    993/udp    # IMAP over SSL

Dans ce dernier exemple, les occurrences de la chaîne de caractères recherchée se situent aux lignes 262 et 263 du fichier /etc/services.

Suivant le nombre de résultats trouvés, grep peut être une commande extrêmement bavarde. Heureusement, il existe plusieurs façons d'obtenir un résultat plus lisible. Reprenons donc notre commande :

$ grep bash /etc/passwd

Au lieu d'afficher toutes les lignes contenant la chaîne de caractères bash, nous allons nous contenter d'afficher leur nombre :

$ grep -c bash /etc/passwd
4

Cette simple commande m'indique donc combien d'utilisateurs de ma machine utilisent le shell Bash.

Chercher du texte dans une série de fichiers

La recherche d'une chaîne de caractères peut porter sur plusieurs fichiers à la fois. Vous verrez cependant que cela pose très vite des problèmes en termes de lisibilité. Pour illustrer ceci, recherchons la chaîne de caractères PS1 dans tous les fichiers du répertoire /etc. Travaillez en tant que root pour éviter les problèmes de permissions :

# grep "PS1" /etc/*
grep: /etc/alternatives: Is a directory
grep: /etc/audisp: Is a directory
grep: /etc/audit: Is a directory
grep: /etc/bash_completion.d: Is a directory
/etc/bashrc:if [ "$PS1" ]; then
/etc/bashrc: [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
/etc/bashrc: # if [ "$PS1" ]; then
/etc/bashrc: #   PS1="[\u@\h:\l \W]\\$ "
/etc/bashrc:           if [ "$PS1" ]; then
grep: /etc/binfmt.d: Is a directory
grep: /etc/chkconfig.d: Is a directory
...

Le résultat de cette opération ressemble à un succès partiel. L'occurrence de PS1 est bien détectée dans les fichiers /etc/bashrc et /etc/sudoers, au beau milieu d'une avalanche d'avertissements. En effet, grep ne peut chercher du texte que dans des fichiers au format texte... et pas dans des répertoires à proprement parler.

Comme nous l'avons vu précédemment, nous pouvons faire fi des erreurs en les redirigeant vers /dev/null. Recommençons :

# grep "PS1" /etc/* 2> /dev/null
/etc/bashrc:if [ "$PS1" ]; then
/etc/bashrc: [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
/etc/bashrc: # if [ "$PS1" ]; then
/etc/bashrc: #   PS1="[\u@\h:\l \W]\\$ "
/etc/bashrc:           if [ "$PS1" ]; then
/etc/sudoers:Defaults env_keep += "MAIL PS1 PS2 QTDIR ..."

Essayons maintenant de chercher la chaîne de caractères TERM dans les fichiers du répertoire /etc :

# grep "TERM" /etc/* 2> /dev/null

Les résultats de la recherche inondent la console et l'ensemble souffre d'un manque de lisibilité. Dans certains cas, l'abondance des occurrences rend ce genre de requête à peu près inutilisable.

Retentons avec l'option -l, qui nous affiche simplement le nom des fichiers dans lesquels il y a au moins une occurrence :

# grep -l "TERM" /etc/* 2> /dev/null
/etc/bashrc
/etc/csh.cshrc
/etc/DIR_COLORS
/etc/DIR_COLORS.256color
/etc/DIR_COLORS.lightbgcolor

Maintenant, essayons la même chose avec une approche différente. L'option -maxdepth 1 indique à find de ne pas descendre dans les sous-répertoires pour sa recherche :

# find /etc -maxdepth 1 -type f | xargs grep -l "TERM"
/etc/bashrc
/etc/csh.cshrc
/etc/DIR_COLORS.lightbgcolor
/etc/DIR_COLORS.256color
/etc/DIR_COLORS

Affiner la recherche

Pareillement, il arrive qu'une chaîne de caractères présente de très nombreuses occurrences dans un fichier, ce qui ne facilite pas exactement la recherche :

$ grep "at" /etc/services

Vous constatez que la chaîne de caractères at semble omniprésente dans ce fichier ; c'est normal, puisqu'elle fait partie d'un grand nombre de mots de la langue anglaise. Dans ce cas, nous pouvons peaufiner notre recherche, par exemple en lançant une requête sur toutes les lignes qui commencent par at :

$ grep "^at" /etc/services
at-rtmp    201/tcp    # AppleTalk routing
at-rtmp    201/udp
at-nbp     202/tcp    # AppleTalk name binding
at-nbp     202/udp
at-echo    204/tcp    # AppleTalk echo
at-echo    204/udp
at-zis     206/tcp    # AppleTalk zone information
at-zis     206/udp
...

De façon analogue, je peux également rechercher toutes les lignes qui finissent par une certaine chaîne de caractères, par exemple toutes celles du fichier /etc/services qui comportent DNS à la fin :

$ grep "DNS$" /etc/services
menandmice-dns  1337/tcp    # menandmice DNS
menandmice-dns  1337/udp    # menandmice DNS
mdns            5353/tcp    # Multicast DNS
mdns            5353/udp    # Multicast DNS

Les possibilités de grep sont extrêmement variées. C'est un véritable couteau suisse de la recherche de chaînes de caractères dans un système de fichiers. Nous nous arrêterons là pour l'instant. Les applications de grep que nous avons vues jusqu'ici nous permettent déjà de faire un bon bout de chemin dans la pratique.

Obtenir des informations sur son matériel

Voyons maintenant une série d'applications pratiques des techniques de filtrage avec la commande lspci, qui liste les périphériques installés dans votre machine.

$ lspci

Pour extraire des renseignements plus précis dans tout ce flot d'informations, il suffit que je combine la commande lspci avec grep. Admettons que j'aie juste besoin de me renseigner sur la carte vidéo de ma machine :

$ lspci | grep -i vga
00:02.0 VGA compatible controller: Intel Corporation 82G33/G31 
Express Integrated Graphics Controller (rev 02) 

Il en va de même pour la carte son :

$ lspci | grep -i audio
00:1b.0 Audio device: Intel Corporation NM10/ICH7 Family 
High Definition Audio Controller (rev 01)

Et voici la commande pour la carte Ethernet :

$ lspci | grep -i eth
02:00.0 Ethernet controller: Broadcom Corporation NetLink BCM5787 
Gigabit Ethernet PCI Express (rev 02)

Je peux filtrer l'affichage de /proc/cpuinfo pour connaître le nombre de processeurs sur la machine. Voilà ce que cela donne sur ma station de travail munie d'un processeur Intel Core i7 :

$ grep "processor" /proc/cpuinfo 
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7

L'utilisation de grep ne s'arrête pas là, mais je pense que les exemples présentés vous ont aidé à en saisir le principe.


La rédaction de ces cours demande du temps et des quantités significatives de café espresso. Vous appréciez cette formation ? Offrez un café au formateur.