Utilisation du signe astrologique dans grep

87

J'essaye de rechercher la sous-chaîne "abc" dans un fichier spécifique sous linux / bash

Moi aussi:

grep '*abc*' myFile

Il ne renvoie rien.

Mais si je fais:

grep 'abc' myFile

Il renvoie correctement les correspondances.

Maintenant, ce n'est pas un problème pour moi. Mais que faire si je veux grep pour une chaîne plus complexe, disons

*abc * def *

Comment pourrais-je y parvenir en utilisant grep?

Saobi
la source
3
grep lui-même ne prend pas en charge les caractères génériques sur la plupart des plateformes. Vous devez utiliser egrep pour utiliser des caractères génériques. Les shells ont une syntaxe différente. "*" dans le shell est <toute chaîne>. Dans egrep, c'est un opérateur qui dit "0 à plusieurs de l'entité précédente". Dans grep, c'est juste un caractère normal.
PanCrit
@PanCrit: *signifie la même chose dans grep et egrep: c'est un quantificateur signifiant zéro ou plus de l'atome précédent. C'est un concept complètement différent des caractères génériques utilisés par le shell.
Alan Moore

Réponses:

123

L'astérisque n'est qu'un opérateur de répétition , mais vous devez lui dire ce que vous répétez. /*abc*/correspond à une chaîne contenant ab et zéro ou plus de c (parce que le deuxième * est sur le c; le premier n'a pas de sens parce qu'il n'y a rien à répéter). Si vous voulez faire correspondre quelque chose, vous devez dire .*- le point signifie n'importe quel caractère ( selon certaines directives ). Si vous voulez simplement faire correspondre abc, vous pouvez simplement dire grep 'abc' myFile. Pour votre correspondance plus complexe, vous devez utiliser .*- grep 'abc.*def' myFilecorrespondra à une chaîne contenant abc suivie de def avec quelque chose éventuellement entre les deux.

Mise à jour basée sur un commentaire:

*dans une expression régulière n'est pas exactement la même chose que * dans la console. Dans la console, * fait partie d'une construction glob , et agit simplement comme un joker (par exemple ls *.log, listera tous les fichiers qui se terminent par .log). Cependant, dans les expressions régulières, * est un modificateur, ce qui signifie qu'il s'applique uniquement au caractère ou au groupe qui le précède. Si vous voulez que * dans les expressions régulières agisse comme un caractère générique, vous devez utiliser .*comme mentionné précédemment - le point est un caractère générique, et l'étoile, lors de la modification du point, signifie trouver un ou plusieurs points; c'est à dire. trouver un ou plusieurs de n'importe quel caractère.

Daniel Vandersluis
la source
1
Je pense que le questionneur est confus quant à la différence entre les caractères génériques de shell et les expressions régulières. Je soupçonne également que l'expression la plus compliquée serait: grep 'abc. * Def' (au moins un espace présent - peut-être deux comme je l'ai écrit).
Jonathan Leffler
1
En fait, le questionneur semble ne pas comprendre que 'abc' n'est pas la même chose que '^ abc $' :-D
Massa
1
Oui, j'étais confus entre glob et les expressions régulières complètes. J'utilise le * sans point pour signifier correspondre à quoi que ce soit sur le shell.
Saobi
1
grep *signifie "0 ou plus", et grep est gourmand par défaut. Notez que dans grep base des expressions régulières les métacaractères ?, +, {, |, (et )perdent leur signification particulière. Plus d'informations: grep regexps
KrisWebDev
24

Le caractère point signifie correspondre à n'importe quel caractère, donc .*zéro ou plusieurs occurrences de n'importe quel caractère. Vous voulez probablement utiliser .*plutôt que simplement *.

smcameron
la source
Le point est un méta caractère qui accepte n'importe quel caractère sauf les nouvelles lignes .
Abhishek Kamal
12

Le "signe astrologique" n'a de sens que s'il y a quelque chose devant lui. S'il n'y a pas l'outil (grep dans ce cas) peut simplement le traiter comme une erreur. Par exemple:

'*xyz'    is meaningless
'a*xyz'   means zero or more occurrences of 'a' followed by xyz
Jonathan Leffler
la source
5
Le * n'a pas de sens; il n'a tout simplement pas sa signification habituelle (de répétition) mais signifie "je suis une star". Cela correspondrait à une ligne contenant une étoile suivie de x, y et z.
Jonathan Leffler
2
@Jonathan Cela dépend de l'outil.
7

Utilisez grep -P - qui active la prise en charge des expressions régulières de style Perl.

grep -P "abc.*def" myfile
Artem Russakovskii
la source
6

L'expression que vous avez essayée, comme celles qui fonctionnent sur la ligne de commande du shell sous Linux par exemple, s'appelle un " glob ". Les expressions globales ne sont pas des expressions régulières complètes , ce que grep utilise pour spécifier les chaînes à rechercher. Voici un (ancien, petit) post sur les différences. Les expressions glob (comme dans "ls *") sont interprétées par le shell lui-même.

Il est possible de traduire des globes en RE, mais vous devez généralement le faire dans votre tête.

se détendre
la source
1
Ce n'est qu'un glob s'il est analysé par le shell. Puisqu'il préserve la chaîne de recherche à l'intérieur de guillemets simples, le shell laisse la chaîne seule et la passe intacte dans argv à grep.
Compilateur remarquable
4

Vous n'utilisez pas d'expressions régulières, donc la variante grep de votre choix devrait être fgrep, qui se comportera comme vous l'attendez.

Andrew Beals
la source
2
fgrepest désormais obsolète, grep -fdoit être utilisé à la place.
Prometheus
1
C'est "grep -F". Le bon vieux fgrep est peut-être "obsolète", mais ils ne vont pas le supprimer tant que je suis encore en vie.
Andrew Beals
1

C'est peut-être la réponse que vous recherchez:

grep abc MyFile | grep def

La seule chose est que ... il affichera les lignes où "def" est avant OU après "abc"

Charles Duke
la source
1

Cela a fonctionné pour moi:

grep ". * $ {expr}" - avec des guillemets doubles, précédés du point. Où "expr" est la chaîne dont vous avez besoin à la fin de la ligne.

Grep unix standard sans commutateurs supplémentaires.

accès autorisé
la source
0

'*' fonctionne comme un modificateur pour l'élément précédent. Donc 'abc * def' recherche 'ab' suivi de 0 ou plus de 'c suivis de' def '.

Ce que vous voulez probablement, c'est "abc. * Def" qui recherche "abc" suivi d'un nombre quelconque de caractères, suivi de "def".

Compilateur remarquable
la source