977 votes

Est-ce que grep peut montrer seulement les mots qui correspondent au modèle de recherche ?

Existe-t-il un moyen de faire en sorte que grep produise des "mots" à partir des fichiers qui correspondent à l'expression de recherche ?

Si je veux trouver toutes les instances de, disons, "th" dans un certain nombre de fichiers, je peux le faire :

grep "th" *

mais le résultat sera quelque chose comme (les caractères gras sont de moi) ;

some-text-file : **the** cat sat on **the** mat  
some-other-text-file : **the** quick brown fox  
yet-another-text-file : i hope **this** explains it **thoroughly** 

Ce que je veux qu'il produise, en utilisant la même recherche, c'est :

the
the
the
this
thoroughly

Est-ce possible en utilisant grep ? Ou en utilisant une autre combinaison d'outils ?

7 votes

La solution de Dan Midwood fonctionne parfaitement et mérite le crédit.

0 votes

Existe-t-il un moyen d'imprimer ces mots appariés sans modifier les lignes ? La chaîne de caractères correspondante devrait plutôt rester sur la même ligne ?

1390voto

Dan Midwood Points 2569

Essayez grep -o :

grep -oh "\w*th\w*" *

Edit : correspondance avec le commentaire de Phil.

Desde les docs :

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.

14 votes

@user181548, L'option grep -o ne fonctionne que pour GNU grep. Donc si vous n'utilisez pas GNU grep, il se peut qu'elle ne fonctionne pas pour vous.

5 votes

@A-B-B Cela dépend si vous voulez afficher le nom du fichier correspondant ou non. Je ne suis pas sûr des conditions dans lesquelles il affiche et n'affiche pas, mais je sais que lorsque j'ai utilisé grep sur un certain nombre de répertoires, il a affiché le chemin d'accès complet de tous les fichiers correspondants, alors qu'avec -h, il a juste affiché les mots correspondants sans aucune spécification sur le fichier en question. Donc, pour répondre à la question originale, je pense que c'est nécessaire dans certaines circonstances.

7 votes

J'avais besoin d'une explication pour ce que "\w*th\w*" * signifie, donc j'ai pensé que je posterais. \w est [_[:alnum :]], ce qui correspond à n'importe quel "mot" qui contient "th" (car \w ne comprend pas d'espace). L'astérisque (*) après la section citée est un glob pour les fichiers (c'est-à-dire qu'il correspond à tous les fichiers de ce répertoire).

109voto

pico.creator Points 4094

Réponse sûre à la distribution croisée (y compris Windows minGW ?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

Si vous utilisez des versions plus anciennes de grep (comme 2.4.2) qui n'incluent pas l'option -o, alors utilisez la méthode ci-dessus. Sinon, utilisez la version plus simple à maintenir ci-dessous.

Réponse sûre à la distribution croisée de Linux

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

Pour résumer : -oh produit l'expression régulière correspondant au contenu du fichier (et non à son nom de fichier), tout comme on pourrait s'attendre à ce qu'une expression régulière fonctionne dans vim/etc.... Le mot ou l'expression régulière que vous recherchez alors, c'est vous qui décidez ! Tant que vous restez dans le cadre de POSIX et non de la syntaxe perl (voir ci-dessous).

Plus du manuel pour grep

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

La raison pour laquelle la réponse originale ne fonctionne pas pour tout le monde

L'utilisation de \w varie d'une plate-forme à l'autre, car il s'agit d'une syntaxe "perl" étendue. En tant que telles, les installations grep qui sont limitées au travail avec les classes de caractères POSIX utilisent [[:alpha:]] et non son équivalent perl de \w . Voir la page Wikipedia sur les expressions régulières pour plus d'informations

Au final, la réponse POSIX ci-dessus sera beaucoup plus fiable quelle que soit la plateforme (étant l'original) pour grep

En ce qui concerne le support de grep sans l'option -o, le premier grep sort les lignes pertinentes, le tr divise les espaces en nouvelles lignes, le dernier grep ne filtre que les lignes respectives.

(PS : je sais que la plupart des plates-formes auraient déjà été corrigées pour le \w.... mais il y a toujours ceux qui sont à la traîne)

La solution de contournement "-o" est due à la réponse de @AdamRosenfield.

1 votes

Qu'en est-il de -o qui ne fonctionne que dans GNU grep (comme ksinkar l'a mentionné dans un commentaire sur la réponse acceptée) ?

0 votes

@Brilliand hmm, j'ai du mal à trouver une implémentation linux qui ne supporte pas '-o', je peux chercher une solution de contournement si je sais sur quelle plateforme vérifier.

0 votes

@pico The -o n'est pas présente dans le grep de Windows qui est installé avec le paquet git (minGW ?): "c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2

51voto

Adam Rosenfield Points 176408

Vous pourriez traduire les espaces en nouvelles lignes et ensuite grep, par exemple :

cat * | tr ' ' '\n' | grep th

23 votes

Pas besoin de chat. tr ' ' ' \n ' < fichier | grep th. Lent pour les gros fichiers.

0 votes

Cela n'a pas fonctionné. La sortie contenait toujours le nom du fichier et la ligne entière du fichier qui contenait la correspondance. Quoi qu'il en soit, l'une des autres solutions proposées a fonctionné. Merci quand même pour votre contribution.

0 votes

@ghostdog74 : bon point, bien que si vous avez plus que le fichier, vous devrez utiliser cat. @Neil Baldwin : êtes-vous sûr de l'avoir tapé correctement ? Lorsqu'il n'y a qu'un seul fichier d'entrée (stdin dans ce cas), grep n'imprime pas le nom du fichier.

42voto

ghostdog74 Points 86060

Juste awk Il n'est pas nécessaire de combiner plusieurs outils.

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly

10voto

Beau Points 3353

Je n'étais pas satisfait de la syntaxe difficile à mémoriser d'awk, mais j'aimais l'idée d'utiliser un utilitaire pour faire cela.

Il semble que ack (ou ack-grep si vous utilisez Ubuntu) puisse faire cela facilement :

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

Si vous omettez le drapeau -h vous obtenez :

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

En prime, vous pouvez utiliser le --output flag pour effectuer des recherches plus complexes avec la syntaxe la plus simple que j'ai trouvée :

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X