comment utiliser l'option grep --include pour plusieurs types de fichiers?

98

Quand je veux grep tous les fichiers html dans un répertoire, je fais ce qui suit

grep --include="*.html" pattern -R /some/path

qui fonctionne bien. Le problème est de savoir comment grep tous les fichiers html, htm, php dans un répertoire?

À partir de cela, utilisez grep --exclude / - include syntax pour ne pas grep via certains fichiers , il semble que je puisse faire ce qui suit

grep --include="*.{html,php,htm}" pattern -R /some/path

Mais malheureusement, cela ne fonctionnerait pas pour moi.
Pour info, ma version grep est 2.5.1.

tianyapiaozi
la source

Réponses:

140

Vous pouvez utiliser plusieurs --includeindicateurs. Cela fonctionne pour moi:

grep -r --include=*.html --include=*.php --include=*.htm "pattern" /some/path/

Cependant, vous pouvez faire comme Deruijtersuggéré. Cela fonctionne pour moi:

grep -r --include=*.{html,php,htm} "pattern" /some/path/

N'oubliez pas que vous pouvez utiliser findet xargspour ce genre de chose pour:

find /some/path/ -name "*.htm*" -or -name "*.php" | xargs grep "pattern"

HTH

Steve
la source
1
Je vois le problème. J'ai utilisé --include = " . { Html , php}" pour empêcher le shell de se développer ' ', ce qui en même temps empêche le shell de se développer {html, php}. Il semble que le signe égal dans --include = * soit capable d'empêcher le shell de développer '*'.
tianyapiaozi
xargs n'est pas vraiment un substitut; souvent, lorsque vous avez besoin de cette fonctionnalité, vous avez affaire à plus de fichiers que xargs n'en gérera.
James Moore
2
@JamesMoore: Jetez un œil à GNU Parallel . Il peut souvent être utilisé comme substitut de xargs. Cela vaut également la peine d'être lu rapidement. HTH.
Steve
3
@tianyapiaozi: Vous avez raison de dire que les guillemets autour de l'extension d'accolades sont le problème; sans les guillemets, cependant, *est toujours sujet au globbing dans le cadre du jeton dans lequel il est intégré , il se trouve que cela ne correspond à rien dans ce cas, car seuls les fichiers littéralement nommés quelque chose comme --include=foo.htmlcorrespondent. Pour être sûr, citez le *(que pouvez-vous faire individuellement avec \*). En prime, cela rend visuellement plus clair que ce n'est pas le shell qui devrait effectuer le globbing dans ce cas.
mklement0
2
Quant à la findsolution: utiliser -exec grep "pattern" {} +au lieu de | xargs grep "pattern"est plus robuste (gère les noms de fichiers avec des espaces, par exemple) et plus efficace.
mklement0
32

L' utilisation {html,php,htm}ne peut fonctionner comme une expansion des accolades , ce qui est une caractéristique de non standard (non-conforme aux spécifications POSIX) bash, kshet zsh.

  • En d'autres termes: n'essayez pas de l'utiliser dans un script qui cible /bin/sh- utilisez plusieurs arguments explicites--include dans ce cas.

  • greplui-même ne comprend pas la{...} notation.

Pour qu'une extension d'accolade soit reconnue, il doit s'agir d'un jeton non guillemet (partie d'un) sur la ligne de commande.

Une extension d'accolade se développe en plusieurs arguments , donc dans le cas présent grepfinit par voir plusieurs --include=... options, comme si vous les aviez passées individuellement.

Les résultats d'une expansion d'accolades sont sujets au globbing (expansion du nom de fichier) , qui présente des pièges :

  • Chaque argument résultant peut être étendu aux noms de fichiers correspondants s'il contient des métacaractères globuleux sans guillemets tels que* .
    Bien que cela soit peu probable avec des jetons tels que --include=*.html(par exemple, vous devez avoir un fichier nommé littéralement quelque chose comme --include=foo.htmlpour que quelque chose corresponde), cela vaut la peine de garder à l'esprit en général.

  • Si l' nullgloboption shell est activée (shopt -s nullglob ) et que le globbing ne correspond à rien , l'argument sera rejeté .

Par conséquent, pour une solution entièrement robuste , utilisez les éléments suivants:

grep -R '--include=*.'{html,php,htm} pattern /some/path
  • '--include=*.' est traité comme un littéral , car il est entre guillemets simples ; cela empêche une interprétation par inadvertance de *comme un caractère globuleux.

  • {html,php,htm}, l' expansion d'accolades - par nécessité - sans guillemets [1] , se développe en 3 arguments, qui, en raison de {...} suivre directement le'...' jeton , incluent ce jeton.

  • Par conséquent, après la suppression des guillemets par le shell, les 3 arguments littéraux suivants sont finalement passés àgrep :

    • --include=*.html
    • --include=*.php
    • --include=*.htm

[1] Plus précisément, ce ne sont que les parties syntaxiques de l'expansion d'accolades qui doivent être sans guillemets, les éléments de la liste peuvent toujours être entre guillemets individuellement et doivent l'être s'ils contiennent des métacaractères globuleux qui pourraient entraîner un globbing indésirable après l'expansion d'accolades; bien que cela ne soit pas nécessaire dans ce cas, ce qui précède pourrait être écrit comme
'--include=*.'{'html','php','htm'}

mklement0
la source
1
Merci beaucoup pour ce message. Les bons articles répondent non seulement à la question, mais vous apprennent quelque chose de nouveau! Ceci est particulièrement utile pour ceux d'entre nous qui écrivent sur quelque chose qui doit être conforme à POSIX. Toute personne utilisant Mac OS X devrait regarder ici!
sabalaba
@sabalaba: Je suis heureux de l'entendre, mais pour être clair: bien que l'expansion d'accolades ne soit pas conforme à POSIX, elle fonctionne bashsur n'importe quelle plate-forme qui bashfonctionne.
mklement0
9

Essayez de supprimer les guillemets

grep --include=*.{html,php,htm} pattern -R /some/path
Deruijter
la source
@tianyapiaozi Essayez grep --include=\*.{html,php,htm} pattern -R /some/path. Cela a fonctionné pour moi.
Hyunjun Kim
4

cela ne fonctionne pas?

  grep pattern  /some/path/*.{html,php,htm} 
Vijay
la source
Pas vraiment. Les fichiers peuvent résider dans le sous-répertoire du sous
tianyapiaozi
2

Essaye ça. -r fera une recherche récursive. -s supprimera les erreurs de fichier non trouvées. -n vous montrera le numéro de ligne du fichier où se trouve le motif.

    grep "pattern" <path> -r -s -n --include=*.{c,cpp,C,h}
Pradeep
la source
C'est la meilleure réponse pour moi en particulier, et je pense que vous pouvez mettre -rsn au lieu de -r -s -n (mais c'est pinailler).
slim
J'utilise généralement -rns . Pour plus de clarté dans l'exemple, je devais mentionner -r -n -s :-) Heureux que cela ait aidé.
Pradeep
Je recommande d'ajouter -Ià l'ensemble standard. Il ignore les fichiers binaires (qui ne sont pratiquement jamais recherchés), ce qui augmente l'efficacité. Ensuite, nous allons grep -rIns ...qui joue bien en acoustique :)
sanglant
2

Cela fonctionne dans le même but, mais sans --includeoption. Cela fonctionne également sur grep 2.5.1.

grep -v -E ".*\.(html|htm|php)"
Kohei Mikami
la source
0

Utiliser grepavec la findcommande

find /some/path -name '*.html' -o -name '*.htm' -o -name '*.php' -type f 
 -exec grep PATTERN {} \+

Vous pouvez utiliser -regexet les -regextypeoptions aussi.

Prince John Wesley
la source