Si je grep un document qui contient les éléments suivants:
ThisExampleString
... pour l'expression This*String
ou *String
, rien n'est retourné. Cependant, This*
renvoie la ligne ci-dessus comme prévu.
Que l'expression soit placée entre guillemets ne fait aucune différence.
Je pensais que l'astérisque indiquait un certain nombre de caractères inconnus? Pourquoi ça marche seulement si c'est au début de l'expression? S'il s'agit d'un comportement voulu, que dois-je utiliser à la place des expressions This*String
et *String
?
command-line
bash
grep
regex
Trae
la source
la source
* != any number of unknown characters
Réponses:
Un astérisque dans les expressions régulières signifie "correspond à l'élément précédent 0 fois ou plus".
Dans votre cas particulier avec
grep 'This*String' file.txt
, vous essayez de dire: "Hé, grep, faites-moi correspondre le motThi
, suivi des
zéro ou plusieurs fois en minuscule , suivi du motString
". Les minusculess
ne se trouvent nulle part dansExample
, donc grep ignoreThisExampleString
.Dans le cas de
grep '*String' file.txt
, vous dites "grep, correspond moi la chaîne vide - littéralement rien - précédant le motString
". Bien sûr, ce n'est pas comme çaThisExampleString
qu'on doit lire. (Il existe d' autres significations possibles - vous pouvez essayer cela avec et sans le-E
drapeau - mais aucune des significations ne ressemble à ce que vous voulez vraiment ici.)Sachant que
.
nous pourrions faire cela signifie « tout caractère unique »,:grep 'This.*String' file.txt
. Maintenant, la commande grep le lira correctement:This
suivi de n'importe quel caractère (pensez-y comme sélection de caractères ASCII) répété autant de fois, suivi deString
.la source
*
est un caractère spécial et il doit être cité ou échappé par exemple comme ceci:grep 'This*String' file.txt
ou ceci:grep This\*String file.txt
pour ne pas être surpris par des résultats inattendus.*
c'est un caractère générique. Dans grep,*
est un opérateur d'expression régulière. Voir unix.stackexchange.com/q/57957/70524strace grep .* file.txt |& head -n 1
etstrace grep '.*' file.txt |& head -n 1
. Fonctionnegrep
également avec tous les caractères Unicode (par exemple, lesecho -ne ⇏ | grep ⇏
sorties⇏
)bash
. Cela signifie que d'abordbash
interprète ses caractères spéciaux et seulement après toutes les extensions effectuées, il transmet les paramètres au processus généré. ----- Par exemple cette commande dans Bash:grep This.\*String file.txt
pondra/bin/grep
avec ces paramètres 0:grep
1:This.*String
2:file.txt
. Notez que Bash a supprimé la barre oblique inverse et que l'échappement à l'origine a*
été passé littéralement.grep This.*String file.txt
fonctionneront normalement parce qu'il n'y aura probablement pas de fichier correspondant à l'expression générique du shellThis.*String
. Dans un tel cas par défaut, Bash passera l'argument littéralement*
.Le
*
métacaractère dans BRE 1 s, ERE 1 s et PCRE 1 s correspond à 0 occurrence ou plus du modèle précédemment groupé (si un modèle groupé précède le*
métacaractère), 0 ou plusieurs occurrences de la classe de caractères précédente (si une classe de caractères est précédant le*
métacaractère) ou 0 ou plusieurs occurrences du caractère précédent (si ni un motif groupé ni une classe de caractères ne précède le*
métacaractère);Cela signifie que dans le
This*String
modèle, étant le*
métacaractère non précédé d'un modèle groupé ou d'une classe de caractères, le*
métacaractère correspond à 0 occurrence ou plus du caractère précédent (dans ce cas, les
caractère):Pour faire correspondre 0 ou plusieurs occurrences de n'importe quel caractère, vous souhaitez faire correspondre 0 ou plusieurs occurrences du
.
métacaractère, qui correspond à n'importe quel caractère:Le
*
métacaractère dans les BRE et les ERE est toujours "gourmand", c'est-à-dire qu'il correspondra à la correspondance la plus longue:Ce n'est peut-être pas le comportement souhaité; dans le cas contraire, vous pouvez activer le
grep
moteur PCRE de (en utilisant l'-P
option) et ajouter le?
métacaractère qui, une fois placé après les métacaractères*
et,+
a pour effet de changer leur gourmandise:1: Expressions régulières de base, expressions régulières étendues et expressions régulières compatibles Perl
la source
L'une des explications se trouve ici lien :
la source
*
a une signification particulière à la fois en tant que caractère de remplacement de shell ("caractère générique") et en tant que métacaractère d' expression régulière . Vous devez prendre en compte les deux, mais si vous citez votre expression régulière, vous pouvez empêcher le shell de le traiter spécialement et vous assurer qu'il passe inchangé àgrep
. Bien que sorte de semblable sur le plan conceptuel, ce*
moyen de la coquille est tout à fait différent de ce que cela signifiegrep
.Tout d'abord, le shell est traité
*
comme un caractère générique.Tu as dit:
Cela dépend des fichiers qui existent dans le répertoire dans lequel vous vous trouvez lorsque vous exécutez la commande. Pour les modèles qui contiennent le séparateur de répertoires
/
, cela peut dépendre des fichiers qui existent sur l'ensemble de votre système. Vous devez toujours citer les expressions régulières pourgrep
- et les guillemets simples sont généralement les meilleurs - à moins que vous ne soyez sûr d'être d'accord avec les neuf types de transformations potentiellement surprenantes que le shell effectue autrement avant d' exécuter lagrep
commande.Lorsque le shell rencontre un
*
caractère qui n'est pas entre guillemets , il prend pour signifier «zéro ou plus de n'importe quel caractère» et remplace le mot qui le contient par une liste de noms de fichiers qui correspondent au modèle. (Les noms de fichiers commençant par.
sont exclus - sauf si votre modèle lui-même commence par.
ou si vous avez configuré votre shell pour les inclure de toute façon.) Ceci est connu sous le nom de globbing - ainsi que sous les noms expansion de nom de fichier et expansion de nom de chemin .L'effet avec
grep
sera généralement que le premier nom de fichier correspondant est considéré comme l'expression régulière - même s'il serait assez évident pour un lecteur humain qu'il ne s'agit pas d'une expression régulière - tandis que tous les autres noms de fichiers sont automatiquement répertoriés dans votre glob sont considérés comme les fichiers dans lesquels rechercher les correspondances. (Vous ne voyez pas la liste - elle est transmise de manière opaque àgrep
.) Vous ne voulez pratiquement jamais que cela se produise.La raison pour laquelle ce n'est parfois pas un problème - et dans votre cas particulier, du moins jusqu'à présent , ce n'était pas le cas - est que
*
cela sera laissé seul si toutes les conditions suivantes sont vraies :Il n'y avait pas de fichiers dont les noms appariés. ... Ou vous avez désactivé le globbing dans votre shell, généralement avec
set -f
ou l'équivalentset -o noglob
. Mais c'est rare et vous savez probablement que vous l'avez fait.Vous utilisez un shell dont le comportement par défaut est de laisser
*
seul lorsqu'il n'y a aucun nom de fichier correspondant. C'est le cas dans Bash, que vous utilisez probablement , mais pas dans tous les shells de style Bourne. (Le comportement par défaut dans le shell populaire Zsh, par exemple, est que les globs (a) se développent ou (b) produisent une erreur.) ... Ou vous avez changé ce comportement de votre shell - la façon dont cela se fait varie à travers des coquilles.Vous n'avez pas autrement dit à votre shell d'autoriser le remplacement des globs par rien lorsqu'il n'y a pas de fichiers correspondants, ni d'échouer avec un message d'erreur dans cette situation. Dans Bash, cela aurait été fait en activant respectivement l' option shell
nullglob
ou .failglob
Vous pouvez parfois compter sur # 2 et # 3 mais vous pouvez rarement compter sur # 1. Une
grep
commande avec un modèle non cité qui fonctionne maintenant peut cesser de fonctionner lorsque vous avez des fichiers différents ou lorsque vous l'exécutez à partir d'un endroit différent. Citez votre expression régulière et le problème disparaît.Ensuite la
grep
commande traite*
comme un quantificateur.Les autres réponses - comme celles de Sergiy Kolodyazhnyy et de kos - abordent également cet aspect de cette question, de manières quelque peu différentes. J'encourage donc ceux qui ne les ont pas encore lus à le faire, avant ou après avoir lu le reste de cette réponse.
En supposant que le
*
fait se rendre à grep - que la citation devrait garantirgrep
- signifie alors que l'élément qui le précède peut se produire un certain nombre de fois , plutôt que d'avoir à se produire exactement une fois . Cela pourrait encore se produire une fois. Ou il pourrait ne pas être présent du tout. Ou cela pourrait être répété. Le texte correspondant à l' une de ces possibilités sera mis en correspondance.Qu'est-ce que je veux dire par «article»?
Un seul personnage . Depuis
b
matchs un littéralb
,b*
correspond à zéro ou plusb
s, ce quiab*c
correspondac
,abc
,abbc
,abbbc
, etc.De même, étant donné
.
correspond à un caractère ,.*
correspond à zéro ou plusieurs caractères 1 , ainsia.*c
matchsac
,akc
,ahjglhdfjkdlgjdfkshlgc
, mêmeacccccchjckhcc
, etc. OrUne classe de personnages . Depuis
[xy]
matchsx
ouy
,[xy]*
correspond à zéro ou plusieurs caractères où chacun est soitx
ouy
, ce quip[xy]*q
correspondpq
,pxq
,pyq
,pxxq
,pxyq
,pyxq
,pyyq
,pxxxq
,pxxyq
, etc.Cela vaut aussi pour la sténographie formes de classes de personnages comme
\w
,\W
,\s
et\S
. Puisque\w
correspond à n'importe quel caractère de mot,\w*
correspond à zéro ou plusieurs caractères de mot. OuUn groupe . Depuis
\(bar\)
matchsbar
,\(bar\)*
matchs zéro ou plusbar
s, ce quifoo\(bar\)*baz
correspondfoobaz
,foobarbaz
,foobarbarbaz
,foobarbarbarbaz
, etc.Avec les options
-E
ou-P
,grep
traite votre expression régulière comme un ERE ou PCRE respectivement, plutôt que comme un BRE , puis les groupes sont entourés par(
)
au lieu de\(
\)
, vous utiliserez donc à la(bar)
place de\(bar\)
et à lafoo(bar)baz
place defoo\(bar\)baz
.man grep
donne une explication raisonnablement accessible de la syntaxe BRE et ERE à la fin, ainsi qu'une liste de toutes les options de ligne de commandegrep
acceptées au début. Je recommande cette page de manuel comme ressource, ainsi que la documentation GNU Grep et ce site de tutoriel / référence (que j'ai lié à un certain nombre de pages ci-dessus).Pour les tests et l'apprentissage
grep
, je recommande de l'appeler avec un modèle mais sans nom de fichier. Ensuite, il prend l'entrée de votre terminal. Entrez les lignes; les lignes qui vous sont renvoyées en écho sont celles qui contenaient le texte correspondant à votre motif. Pour quitter, appuyez sur Ctrl+ Dau début d'une ligne, qui signale la fin de l'entrée. (Ou vous pouvez appuyer sur Ctrl+ Ccomme avec la plupart des programmes en ligne de commande.) Par exemple:Si vous utilisez l'
--color
indicateur,grep
mettra en évidence les parties spécifiques de vos lignes qui correspondent à votre expression régulière, ce qui est très utile à la fois pour déterminer ce que fait une expression régulière et pour trouver ce que vous recherchez une fois que vous l'avez fait. Par défaut, les utilisateurs d'Ubuntu ont un alias Bash qui provoque l'grep --color=auto
exécution - ce qui est suffisant à cet effet - lorsque vous exécutez àgrep
partir de la ligne de commande, vous n'avez donc probablement même pas besoin de passer--color
manuellement.1 Par conséquent,
.*
dans une expression régulière signifie ce que*
signifie dans un glob shell. Cependant, la différence est qu'imprimegrep
automatiquement les lignes qui contiennent votre correspondance n'importe où , il n'est donc généralement pas nécessaire d'avoir.*
au début ou à la fin d'une expression régulière.la source