Comment rechercher une chaîne dans un fichier PHP en utilisant `grep`?

11

Je recherche une déclaration de classe sur un site avec des centaines de fichiers PHP. Comment puis-je faire cela dans le dossier et les sous-dossiers actuels à l'aide de grep ?

J'ai testé cddans le dossier puis quelque chose comme

grep -r 'class MyClass' *.php
Peter Mortensen
la source
Lorsque cela migre vers le superutilisateur, vous voudrez peut-être dire quelque chose sur ce que vous vouliez qui grep -rne vous a pas donné.
Je suis confus - tu ne viens pas de te répondre? quels ont été les résultats de cette ligne? essayez-vous de l'optimiser davantage? veuillez envisager de lire cette question en tant que quelqu'un d'autre, car elle prête à confusion et n'est pas claire.
meder omuraliev
@autres commentaires: Sa déclaration grep -r ne donne pas ce qu'il veut, sauf si tous les dossiers se terminent par .php, ce qui n'est probablement pas le cas ...
David Oneill
Je n'ai rien reçu du tout. Je suppose que cela n'a pas fonctionné parce que je sais qu'il le trouve lorsque je suis sur le dossier contenant le fichier avec cette classe
J'ai trouvé le fichier par chance. Lors de la recherche du fichier dans le dossier contenant le fichier PHP avec cette ligne, il le trouve (pas besoin de -r). Si je CD à la racine et fais la recherche avec récursivité -r, il ne renvoie rien.

Réponses:

24

Tu peux essayer

grep -r --include=*.php "search string" /path/to/dir
rahul286
la source
1
Fonctionne très bien. J'oublie toujours, mais heureusement, il y a toujours cette réponse pour m'aider. :)
GolezTrol
@GolezTrol Heureux de savoir que :-)
rahul286
9

Je vous recommande d'utiliser quelque chose comme ctags plutôt que de le faire avec un grep. Cependant, si vous le souhaitez, vous pouvez faire quelque chose comme

 find <top level dir> -name \*.php | xargs grep "class MyClass"

Cela suppose bien sûr que vous avez un seul espace entre classet myClassqui pourrait ne pas être vrai. Il est facile de changer l'expression rationnelle pour rechercher un certain nombre d'espaces blancs.

Noufal Ibrahim
la source
4

Si vous utilisez -r, vous souhaiterez probablement rechercher récursivement uniquement le répertoire courant :

grep -r 'class MyClass' .

Notez la période à la fin de ce qui précède.

Ce que vous avez dit, grepc'est que vous vouliez qu'il recherche récursivement chaque *.phpfichier ou répertoire , mais vous n'aviez probablement aucun répertoire se terminant par une extension .php. Ce qui précède est le moyen le plus simple de faire la recherche, mais inclut également des fichiers d'autres types, ce qui est particulièrement problématique lorsque vous avez des répertoires .svn partout. Si vous n'avez pas beaucoup d'autres types de fichiers, ce qui précède est généralement suffisant et fonctionne bien.

La plupart des incarnations de grep n'ont pas de moyen de spécifier les extensions de fichier qui peuvent être recherchées, vous utilisez donc généralement find conjointement avec lui:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} \;

-inameindique à certaines versions de grep que vous souhaitez effectuer une recherche de nom de fichier insensible à la casse, mais que de nombreuses variantes non GNU de find ne le prennent pas en charge, vous pouvez donc l'utiliser à la -nameplace.

L' -execoption ci-dessus a pour effet secondaire d'invoquer grep pour chaque fichier, ce qui est assez coûteux.

D'autres versions de grep prennent en charge un +qui indique à find d'ajouter les arguments ensemble pour réduire le nombre d'appels de l'exécutable:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} + \;

Un moyen fréquemment recommandé de réduire les invocations consiste à utiliser des xargs qui déclencheront grep aussi peu de fois que possible mais autant de fois que nécessaire:

find <startDir> -iname \*.php | xargs grep "class[ \t]*MyClass"

xargsest assez intelligent pour passer grep jusqu'au nombre maximum d'arguments pris en charge sur la ligne de commande, mais la variation ci-dessus ne gère pas très bien certains caractères comme les espaces. Par exemple, si «le fichier.php» un grep de nom de fichier recevrait «le» en tant qu'argument et «fichier.php» en tant qu'argument afin que les deux ne soient pas trouvés. Au lieu de cela, nous utilisons:

find <startDir> -iname \*.php -print0 | xargs -0 grep "class[ \t]*MyClass"

print0et -0travailler ensemble et utiliser des arguments suivis d'un caractère nul pour que l'argument soit complètement et sans ambiguïté identifié.

Si vous avez plus d'un espace après class, ou un onglet, vous voudrez peut-être autoriser plus de caractères en changeant l'expression régulière:class[ \t]*MyClass

Ce message sur StackOverflow contient d'autres exemples et montre comment exclure certains répertoires, comme les répertoires .svn.

Kaleb Pederson
la source
Cela recherche tous les fichiers. Aussi des fichiers qui ne sont pas des fichiers .php.
GolezTrol
J'ai mis à jour le message pour inclure de nombreux autres exemples.
Kaleb Pederson
3

En utilisant l' ack toujours merveilleux ,

ack --php 'class MyClass'
éphémère
la source
1
grep -r 'class MyClass' *.php

va rechercher dans tous les dossiers dont le nom se termine par .php

grep -r 'class MyClass' . | grep .php

recherchera la classe MyClass dans tous les fichiers de tous les sous-dossiers, puis ne renverra que ceux qui contiennent .php.

David Oneill
la source
1

find . -type f -name *.php -print -exec grep \"class MyClass\" {} \; vous donnera le contenu de la ligne sur laquelle il se trouve ainsi que le chemin d'accès au fichier.

prodigitalson
la source
1

Dans le cas où les fichiers correspondants pourraient avoir des noms arbitraires, vous devriez envisager d'utiliser -print0

trouver . -type f -nom '* .php' -print0 | xargs -0 grep 'class MyClass'

wudeng
la source
1
grep -rl 'class MyClass' . --include \*.php

l affiche uniquement le nom de fichier

r est récursif

. recherche dans le dossier actuel

--include limite l'extension du nom de fichier

Plein
la source
1

Vous voulez probablement une insensibilité à la casse et une tolérance aux espaces, et grep se terminera s'il ne trouve aucune instance du modèle de fichier souhaité dans le répertoire courant. Il doit savoir par où commencer, pour ainsi dire, et aucun fichier correspondant ne produit aucun chemin de démarrage.

S'il existe au moins un fichier de l'extension souhaitée, vous pouvez utiliser egrep -ir. findet xargsmontrer leur puissance avec des répertoires simples (mais très gros) sur lesquels grep échoue et des qualificatifs supplémentaires (par exemple si vous souhaitez rechercher des fichiers .inc, .php et php3 uniquement). Mais il perd un peu de commodité et de vitesse dans mon expérience. Pour les déclarations de classe écrites par l'homme, un gros problème sera les espaces blancs. Utilisez donc egrep au lieu de grep. Aussi LC_ALL = C pour une vitesse supplémentaire. Pour plus de commodité, j'utilise souvent:

LC_ALL=C egrep -irn "class[ ]*myclass([ ]|\n)" * | egrep "\.(inc|php[35]?)"

-i -- case insensitive
-r -- recursive for all file pattern (here *)
-n -- include the line number
LC_ALL=C -- search in ASCII, not in utf8, this is much faster.

[ ]* -- match any number of spaces before the class name
([ ]|\n) -- match a space or newline after the classname

Cela peut toujours correspondre à des commentaires, tels que // class myclass exists in file, mais je trouve qu'ils sont relativement petits, et ils peuvent être filtrés avec... | fgrep -v '//'

Vous pouvez également inclure des masques de fichiers plus complexes (par exemple, pour intercepter la plupart des fichiers .inc et .php) sur le modèle de fichier egrep comme ceci:

egrep "pattern" *.[ip]*

Cela (avec les premières options) sera assez rapide et principalement limité aux fichiers php.

HTH

Beracah
la source
0

Je sais que cela dit d'utiliser grep, mais mon préféré est d'utiliser ack-grep:

ack-grep "class MyClass"

Cela s'exécute récursivement, répertorie le nom du fichier dans lequel il trouve les résultats, avec les numéros de ligne pour leur emplacement et les met en surbrillance. Pour cibler spécifiquement les fichiers php, vous pouvez exécuter:

ack-grep --type-set php:ext:php "path"

Le paquet a une pléthore d'options; Je le recommanderais certainement (et parcourant sa page de manuel associée) pour faire des choses fantaisistes.

jhaagsma
la source