Comment utiliser la commande «grep» pour rechercher du texte, y compris des sous-répertoires


373

Je veux trouver tous les fichiers contenant une chaîne de texte spécifique. La grepcommande fonctionne, mais je ne sais pas comment l'utiliser pour tous les répertoires (je ne peux le faire que pour mon répertoire actuel). J'ai essayé de lire man grep, mais cela ne m'a pas aidé.


grep -RIn <votre modèle> * Effectue une recherche dans les répertoires actuels de tous les fichiers texte. Je ne sais pas comment faire ma recherche de manière récursive dans des modèles de fichiers tels que * .C avec seulement grep

1
--include="*.C"Caractère générique avec l' option, @ user311346, grâce à @Lekensteyn.
Bob Stein

Utilisez les combinaisons find et grep pour rechercher de manière récursive dans les fichiers une chaîne dans les sous-répertoires actuels et dans tous les sous-répertoires. Vérifiez ce wilddiary.com/find-files-containing-my-text
Drona

Réponses:


487

Il serait préférable d'utiliser

grep -rl "string" /path

  • -r(ou --recursive) permet de parcourir également tous les sous-répertoires de /path, alors que
  • -l(ou --files-with-matches) option est utilisée pour imprimer uniquement les noms de fichiers des fichiers correspondants, et non les lignes correspondantes (cela pourrait également améliorer la vitesse, étant donné que la greplecture d'un fichier lors de la première correspondance avec cette option).

13
En fait, si "chaîne" est un motif de texte à rechercher, il est préférable d'utiliser cette fonctionnalité, sinon quelqu'un peut faire face à des problèmes lorsque la chaîne contient un point ou un caractère spécial qui a une signification dans les expressions régulières et pas simplement un point qui doit être trouvé sous forme de chaîne. , comme si. Ensuite, je voudrais utiliser des -rlFcommutateurs, -Fpour "chaîne fixe" (et non pas regexp - par exemple). Bien sûr, si la tâche utilisait les expressions rationnelles, alors excusez-moi. Bien sûr, la même théorie sans -r aussi, je vois souvent que les gens partent du principe que grep cherche "texte" et que cela peut poser des problèmes particuliers, qui signifient quelque chose comme une expression rationnelle.
LGB

4
Il y a aussi le -idrapeau qui ignore la casse.
Marco Ceppi

3
Je voudrais seulement montrer l' --recursiveoption, il y a une tonne d'options et de scénarios d'utilisation dont on peut parler. J'ai commencé à partir de la réponse acceptée de @dmityugov et modifié pour fonctionner sans find.
enzotib

1
@NN: terminé :-)
enzotib

3
@ScottBiggs: avec l'option--include '*.h'
enzotib

167

Si vous recherchez des lignes correspondant aux fichiers, ma commande préférée est:

grep -Hrn 'search term' path/to/files
  • -H provoque l'impression du nom de fichier (implicite lorsque plusieurs fichiers sont recherchés)
  • -r fait une recherche récursive
  • -n provoque l'impression du numéro de ligne

path/to/filespeut être .de chercher dans le répertoire courant

Autres options que je trouve très utiles:

  • -Iignorer les fichiers binaires (complément: -atraiter tous les fichiers en tant que texte)
  • -Ftraiter search termcomme un littéral, pas une expression régulière
  • -i faire une recherche insensible à la casse
  • --color=alwayspour forcer les couleurs, même en passant à travers less. Pour créer lessdes couleurs de support, vous devez utiliser l' -roption:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirutile pour exclure des répertoires comme .svnet .git.

Exemple de sortie


13
-Hsur un dossier est redondant, s'il y a plus d'un fichier, comme cela est probable. En fait, la page de manuel dit-H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
enzotib

Je ne le savais pas, cela a toujours fonctionné comme prévu. C'est ma commande par défaut lors de la recherche de fichiers.
Lekensteyn

1
Existe-t-il un moyen de ne considérer que les fichiers avec, par exemple, une extension .a (et de combiner cela avec -r)?
user2413

6
@ user2413 Essayez--include '*.*'
Lekensteyn

1
@alper Trygrep --exclude='*~' ...
Lekensteyn le

24

Je crois que vous pouvez utiliser quelque chose comme ceci:

find /path -type f -exec grep -l "string" {} \;

Explication des commentaires

findest une commande qui vous permet de rechercher des fichiers et d'autres objets tels que des répertoires et des liens dans les sous-répertoires d'un chemin donné. Si vous ne spécifiez pas de masque que les noms de fichiers doivent rencontrer, il énumère tous les objets de répertoire.

  • -type f spécifie qu'il ne devrait traiter que des fichiers, pas des répertoires, etc.
  • -exec grepspécifie que pour chaque fichier trouvé, il doit exécuter la commande grep, en lui passant son nom de fichier en tant qu'argument, en le remplaçant {}par le nom de fichier

3
Pour ceux qui ne le savent pas, ajouter -name '*.py'limite les correspondances aux fichiers se terminant par '.py'.
Daniel F

J'aime que cela couvre les clients pour lesquels -R n'est pas implémenté dans leur commande grep.
Aviose

Si vous voulez que la ligne ET le nom du fichier correspondant soient imprimés, exécutez exec comme:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee

Quelle est la performance relative à l'utilisation de grep directement?
Jonathan

19

Ma commande par défaut est

grep -Rin string *

J'utilise un Capitole 'R' parce que lsje l'utilise pour le traitement récursif. Puisque grep accepte les deux, aucune raison de ne pas l'utiliser.

EDIT: par HVNSweeting, apparemment -Rsuivra des liens symboliques où ne le -rfera pas.


1
Pour rechercher aussi dans les fichiers cachés, lancez shopt -s dotglob(rappelez-vous -scomme "set"). Soyez prudent lorsque vous supprimez des fichiers alors. Si vous avez activé dotglob, rm -r *supprime tout ce qui se trouve dans le répertoire en cours, mais aussi le répertoire situé au-dessus, car les ..correspondances. Pour désactiver dotglob, utilisez shopt -u dotglob("unset"). Les modifications sont temporaires mais ne s’appliquent qu’au shell actuel.
Lekensteyn

J'ai oublié à ce sujet. Y at-il un moyen de le définir pour une ligne? quelque chose comme shopt -s dotglob & <grep cmd> & shopt -y dotglobseulement plus pratique? De cette façon, nous n'aurons pas à nous soucier de le réinitialiser
user606723

Aussi, il est probablement plus facile à utiliser grep -Rin string .dans la plupart des cas. Je viens d'utiliser * parce que cela semble venir plus naturellement.
user606723

1
si vous faites un grep récursif, vous pouvez simplement commencer par "." au lieu de "*". pas besoin de pointglob.
Michał Šrajer

1
votez pour ceci, une chose n'est pas mentionnée dans la page de manuel, c'est de Rsuivre les liens symboliques, rmais pas
HVNSweeting

12

Si vous êtes prêt à essayer quelque chose de nouveau, tentez ackvotre chance. La commande pour rechercher récursivement le répertoire actuel stringest la suivante:

ack string

L'installation est assez simple:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(À condition que vous ayez déjà le répertoire ~/binet qu'il soit de préférence dans votre PATH.)


2
Ou juste apt-get install ack-grep (et ajoutez l'alias ack = ack-grep à votre .bashrc)
markijbema

Que font les derniers paramètres de la chmodcommande? Sont-ils spécifiques chmodou sont-ils liés à la bash (la !#:3partie)?
Elliott Darfink

@ ElliottDarfink qui utilise la fonction d'historique de Bash - !est un indicateur d' événement . Ils sont assez puissants pour éviter les répétitions. !#:3fait référence au troisième jeton de la ligne de commande jusqu'à présent, c'est- ~/bin/ackà- dire dans ce cas.
Konrad Rudolph

4

La commande rgrep est dédiée à ce besoin

Si non disponible, vous pouvez l'obtenir comme ceci

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Vous pouvez directement définir vos options grep par défaut comme décrit ci-dessus.

J'utilise personnellement

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

Sujet connexe: comment utiliser toujours rgrep couleur


rgrep est fourni par le paquetage grep installé par défaut dans Ubuntu.
Karel

2

Mise à jour 2:

Cette ligne de commandes utilisant findet grepcorrige le problème:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> pour une sortie en couleur:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Exemple:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Un exemple exécuté dans l'instantané ci-dessous: claquer1


Mise à jour 1:

Vous pouvez essayer le code suivant. en fonction de votre .bashrcou .bash_aliasesou dans un script:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Usage: wherein /path/to/search/in/ searchkeyword

exemple:

$ wherein ~/Documents/ "hello world"

(Remarque: comme @enzotib le suggère dans les commentaires ci-dessous, cela ne fonctionne pas avec les fichiers / répertoires incluant des espaces dans leurs noms.)


Original post

Pour rechercher la chaîne et afficher uniquement cette ligne avec la chaîne de recherche:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

par exemple:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Pour afficher le nom de fichier contenant la chaîne de recherche:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

par exemple:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;

Échec sur les noms de fichiers contenant des espaces. Le défaut est masqué par le fait que stderr n’est pas montré.
enzotib

@enzotib merci de nous l'avoir signalé .. le problème n'a toujours pas été résolu pour la fonction spécifiée .. J'ai ajouté un autre one-liner cependant ..
précisée le

Maintenant, la réponse est similaire à celle de @dmityugov.
enzotib

oui, mais dans ce sens, la plupart des réponses de cette page si vous cochez la case qu'elles utilisent sont similaires grep, à côté du sous-ensemble utilisant findavec grep... probablement le mien conviendra ici aussi .. ou êtes-vous différent? la dernière mise à jour fait ce que je voudrais dans ma recherche: noms de fichiers avec des lignes avec la clé de recherche et numéro de ligne. too :) et une sortie colorée et un filtre d'erreur pour une meilleure lisibilité ..
précis

2

grep( GNU ou BSD )

Vous pouvez utiliser greptool pour rechercher de manière récursive le dossier actuel avec -rparamètre, comme:

grep -r "pattern" .

Remarque: -r- Recherchez de manière récursive les sous-répertoires.

Pour effectuer une recherche dans des fichiers spécifiques, vous pouvez utiliser une syntaxe globale telle que:

grep "class foo" **/*.c

Remarque: En utilisant l' option globbing ( **), il analyse tous les fichiers de manière récursive avec une extension ou un motif spécifique. Pour activer cette syntaxe, exécutez: shopt -s globstar. Vous pouvez également utiliser **/*.*pour tous les fichiers (sauf les fichiers cachés et sans extension) ou tout autre motif.

Si vous estimez que votre argument est trop long, envisagez de préciser votre recherche ou utilisez findplutôt la syntaxe suivante:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

Alternativement utiliser ripgrep.

ripgrep

Si vous travaillez sur des projets plus volumineux ou de gros fichiers, utilisez ripgrepplutôt:

rg "pattern" .

Consultez la documentation, les étapes d'installation ou le code source sur la page du projet GitHub .

Il est beaucoup plus rapide que tout autre outil comme GNU / BSD grep , ucg, ag, sift, ack, ptou similaire, puisqu'il est construit sur le dessus du moteur de regex de rouille qui utilise des automates finis, SIMD et optimisations littérales agressives pour faire une recherche très rapide.

Il prend en charge les modèles ignorer spécifiés dans les .gitignorefichiers, donc un seul chemin de fichier peut être en correspondance avec plusieurs modèles de glob simultanément.


Vous pouvez utiliser les paramètres communs tels que:

  • -i - Recherche insensible.
  • -I - Ignorer les fichiers binaires.
  • -w - Rechercher les mots entiers (par opposition à la correspondance partielle des mots).
  • -n - Montre la ligne de ton match.
  • -C/ --context(eg -C5) - Augmente le contexte pour que vous voyiez le code qui l'entoure.
  • --color=auto - Marquez le texte correspondant.
  • -H - Affiche le nom du fichier où se trouve le texte.
  • -c- Affiche le nombre de lignes correspondantes. Peut être combiné avec -H.

1

Je le fais en utilisant xargs, une commande très sous-estimée

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ vous donne une liste récursive de tous les fichiers d'un dossier en cours, puis dirigez-le vers xargs qui exécute la commande grep sur chacun de ces fichiers.


4
L'utilisation de xargssans -print0option to findet -0to xargsest obsolète, les noms de fichiers contenant des espaces échouent.
enzotib

@enzotib J'ai modifié la réponse comme vous l'avez suggéré. Veuillez réviser et, si besoin est, de modifier et de corriger, je me ferai un plaisir de la rééditer. merci
αғsнιη le

1
@KasiyA: ça va maintenant, j'ai retiré mon vote négatif.
enzotib

0

Je sais qu'il y a beaucoup de réponses ici, mais voici une alternative si vous souhaitez ajouter d'autres restrictions lors de la recherche dans les fichiers:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Cela fonctionne car grepretournera 0 s'il a trouvé un résultat, 1 sinon. Par exemple, vous pouvez trouver des fichiers de 1 Mo et contenant quelque chose:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

Pour plusieurs besoins, vous souhaiterez probablement utiliser l'indicateur d'optimiseur -Oexistant dans GNU grep.


0

Un script (find-in-code) pour rechercher en C, code CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Utilisation:

find-in-code "search string"
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.