Comment puis-je rechercher une chaîne dans un fichier PHP à l'aide de `grep`?

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

J'ai testé cd ing dans le dossier et quelque chose comme

 grep -r 'class MyClass' *.php 

Tu peux essayer

 grep -r --include=*.php "search string" /path/to/dir 

Je recommanderais que vous utilisiez 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" 

Ceci suppose bien que vous ayez juste un espace entre class et myClass qui pourrait ne pas être vrai. Il est facile de changer le regexp pour rechercher n'importe quel nombre d'espaces blancs.

Si vous utilisez -r , vous souhaitez probablement rechercher de manière récursive uniquement le répertoire actuel :

 grep -r 'class MyClass' . 

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

Ce que vous avez dit à grep c'est que vous vouliez qu'il recherche récursivement tous les fichiers *.php ou répertoire , mais vous n'avez probablement pas de répertoires qui se sont terminés par une extension .php. Ce qui précède est la manière la plus simple possible de faire la recherche, mais comprend également des fichiers d'autres types qui sont particulièrement problématiques lorsque vous disposez de répertoires .svn partout dans le monde. 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 le moyen de spécifier les extensions de fichier qui peuvent être recherchées, de sorte que vous utilisez généralement la recherche conjointement avec elle:

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

-iname dit certaines versions de grep que vous voulez faire une recherche de nom de fichier insensible à la casse, mais beaucoup de variantes non GNU de trouver ne la supporte pas, afin que vous puissiez utiliser -name place.

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

Encore d'autres versions de grep supportent a + qui indique de trouver pour ajouter les arguments ensemble pour réduire le nombre d'invocations de l'exécutable:

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

Une façon fréquemment recommandée de réduire les invocations est d'utiliser xargs qui déclenchera le grep autant de fois que possible, mais autant de fois que nécessaire:

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

xargs est assez intelligent pour passer le grep au nombre maximal d'arguments supportés sur la ligne de commande, mais la variation ci-dessus ne gère pas très bien certains caractères comme des espaces. Par exemple, '' the file.php '' un nom de fichier grep recevrait 'the' comme argument et 'file.php' comme un 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" 

print0 et -0 travaillent ensemble et utilisent des arguments suivis d'un caractère nul afin que l'argument soit complètement et sans ambiguïté identifié.

Si vous avez déjà plus d'un espace après la class ou un onglet, vous pouvez autoriser plus de caractères en modifiant le regex: class[ \t]*MyClass

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

En utilisant l' ack toujours merveilleux,

 ack --php 'class MyClass' 
 grep -r 'class MyClass' *.php 

Recherche tous les dossiers avec des noms se terminant par .php

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

Cherchera la classe MyClass dans tous les fichiers dans tous les sous-dossiers, puis renvoyez ceux qui ont .php dans eux.

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

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

trouver . -type f -name '* .php' -print0 | Xargs -0 grep 'class MyClass'

 grep -rl 'class MyClass' . --include \*.php 

Je ne montre que le nom de fichier

R est récurrent

. Recherches dans le dossier actuel

– inclure les limites de l'extension du nom de fichier

Vous voudrez probablement une insensibilité à la casse et une tolérance d'espace blanc, et grep se terminera s'il ne trouve aucune instance du motif de fichier souhaité dans le répertoire actuel. Il faut savoir par où commencer, et aucun fichier ne correspond à un chemin de départ.

S'il y a au moins un fichier de l'extension souhaitée, vous pouvez utiliser egrep -ir. find et xargs montrent leur pouvoir avec des répertoires simples (mais très grands) que grep échoue et qualificatifs supplémentaires (par exemple, si vous souhaitez rechercher des fichiers .inc, .php et php3 uniquement). Mais il me manque beaucoup de commodité et de rapidité dans mon expérience. Pour les déclarations de classe écrite humaine, un gros problème sera l'espace blanc. 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 encore correspondre aux commentaires, tels que // class myclass exists in file , mais je trouve que ceux-ci sont relativement petits, et ils peuvent être filtrés avec ... | fgrep -v '//' ... | fgrep -v '//'

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

egrep "pattern" *.[ip]*

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

HTH

Je sais qu'il dit 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 qu'il trouve les résultats, avec les numéros de ligne pour l'endroit où ils se trouvent, et met en surbrillance. Pour spécifier spécifiquement les fichiers php, vous pouvez exécuter:

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

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