Trouver une sous-chaîne dans des fichiers à travers des sous-répertoires avec une seule commande intégrée?

10

Sous Windows, si je voulais trouver une chaîne dans tous les fichiers de tous les sous-répertoires, je ferais quelque chose comme

findstr /C:"the string" /S *.h

Cependant, sous Linux ( par exemple, Ubuntu) Je n'ai pas trouvé d' autre moyen que certaines commandes impliquant canalisé find, xargset grep(un exemple est à cette page: Comment puis - je récursive grep à travers les sous-répertoires ). Cependant, ma question est différente: existe-t-il une seule commande intégrée qui fonctionne à travers cette magie, sans avoir à écrire mon script shell?

Guido Domenici
la source

Réponses:

19

GNU grep permet une recherche récursive dans des sous-répertoires:

grep -r --include='*.h' 'the string' .
remuer
la source
J'ai essayé cette ligne de commande exacte dans Ubuntu mais j'obtiens "grep: option invalide - 'M'" bien que je ne puisse voir aucun 'M' n'importe où ... déroutant
Guido Domenici
@Guido fonctionne bien ici
phunehehe
Dans une modification suggérée, TomasG recommande de remplacer le dernier *par '*': "La citation du dernier caractère générique est nécessaire pour éviter les erreurs lorsqu'un nom de fichier commence par -"
Michael Mrozek
Dans une étrange tournure des événements, cela fonctionne maintenant aussi pour moi, comme indiqué dans la réponse originale. Merci!
Guido Domenici
1
@Guido: Votre problème peut être dû à un fichier du répertoire actuel appelé -Msomethingou à un GREP_OPTIONSparamètre.
Gilles 'SO- arrête d'être méchant'
2

grep -r searchpattern /path/to/start/in

/path/to/start/in/peut être juste " ." pour le répertoire courant.

mattdm
la source
1

Non, find -name \*.h -print0 | xargs -0 grep -l 'the regex'c'est aussi magique que possible.

glenn jackman
la source
GNU grep a les cas communs intégrés avec son -roption. Pas besoin d'artillerie lourde.
Gilles 'SO- arrête d'être méchant'
3
xargsajoute juste du bruit. Utilisationfind -name \*.h -execdir grep -l 'the regex {} +
utilisateur inconnu
0

y a-t-il une seule commande intégrée qui fonctionne à travers cette magie ...?

Pour être pédant, non, vous ne pouvez pas supposer qu'une telle commande existe .

Il existe de nombreuses implémentations différentes d'Unix, et chacune a ses différentes particularités. POSIX, le dénominateur commun (et la chose la plus proche d'une norme dans Unices) ne spécifie pas une telle option pourgrep .

Comme mentionné dans d'autres réponses, l'implémentation de GNU grepa une option non standard qui fait ce que vous voulez. Bien que cette implémentation particulière puisse être courante sur les systèmes Linux, vous ne pouvez pas supposer sa disponibilité sur un système Unix, même sur certains systèmes Linux.

Enfin, je dois mentionner que c'est la philosophie Unix de favoriser la combinaison de plusieurs programmes primitifs, plutôt que l'utilisation d'un seul gros exécutable monolithique essayant de tout faire à la fois.

Dans votre cas, l'analyse du système de fichiers et l'expression rationnelle correspondante dans un flux sont deux tâches distinctes. Il est normal de traiter chacun dans un programme distinct.

rahmu
la source
0

Pour rechercher une chaîne dans un répertoire donné, utilisez la commande ci-dessous

find <fullDirectoryPath> -name '*' -exec grep -l '<StringToFind>' {} \;

Par exemple:

find /apps_bev/apps/xfer/export/02210 -name '*' -exec grep -l '38221000001032' {} \;
Yogesh
la source
1
greppeut prendre plus d'un fichier en argument, vous devez donc utiliser +au lieu de \;pour éviter d'exécuter un grepappel par fichier, ce qui est assez inefficace.
Stéphane Chazelas
1
Notez que se -name '*'limite aux fichiers dont le nom est du texte valide dans les paramètres régionaux actuels (dans certaines findimplémentations au moins), mais les autres composants du répertoire peuvent toujours contenir des séquences d'octets qui ne forment pas de caractères valides. Si votre intention -name '*'était de vous assurer que la sortie est du texte valide (en omettant les fichiers avec des noms incorrects), vous préférez utiliser find ... ! -name '*' -prune -o -exec grep ... {} +, ce qui empêcherait également findde descendre dans des répertoires avec des noms incorrects.
Stéphane Chazelas