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 desrwxrwxrwx
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 en cliquant sur la tasse.