*
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 signifie grep
.
Tout d'abord, le shell est traité *
comme un caractère générique.
Tu as dit:
Que l'expression soit placée entre guillemets ne fait aucune différence.
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 pour grep
- 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 la grep
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'équivalent set -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 shellnullglob
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 garantir grep
- 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éral b
, b*
correspond à zéro ou plus b
s, ce qui ab*c
correspond ac
, abc
, abbc
, abbbc
, etc.
De même, étant donné .
correspond à un caractère , .*
correspond à zéro ou plusieurs caractères 1 , ainsi a.*c
matchs ac
, akc
, ahjglhdfjkdlgjdfkshlgc
, même acccccchjckhcc
, etc. Or
Une classe de personnages . Depuis [xy]
matchs x
ou y
, [xy]*
correspond à zéro ou plusieurs caractères où chacun est soit x
ou y
, ce qui p[xy]*q
correspond pq
, 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. Ou
Un groupe . Depuis \(bar\)
matchs bar
, \(bar\)*
matchs zéro ou plus bar
s, ce qui foo\(bar\)*baz
correspond foobaz
, 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 à la foo(bar)baz
place de foo\(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 commande grep
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:
grep 'This.*String'
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'imprime grep
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.
* != any number of unknown characters