Comment fonctionne cette expression de parenthèse dans grep?

38

J'ai vu ce one-liner récemment:

$ ps -ef | grep [f]irefox 

thorsen   16730     1  1 Jun19 ?        00:27:27 /usr/lib/firefox/firefox ...

Donc, il semble retourner la liste des processus avec "firefox" dans les données mais en laissant de côté le processus grep lui-même, et semble donc à peu près équivalent à:

ps -ef |grep -v grep| grep firefox

Je ne comprends pas comment ça marche. J'ai consulté la page de manuel sur grep et ailleurs, mais je n'ai trouvé aucune explication.

Et pour composer le mystère si je cours:

$ ps -ef | grep firefox  > data
$ grep [f]irefox data

thorsen   15820 28618  0 07:28 pts/1    00:00:00 grep --color=auto firefox
thorsen   16730     1  1 Jun19 ?        00:27:45 /usr/lib/firefox/firefox ....

le [t] rick semble cesser de fonctionner!

Quelqu'un ici saura ce qui se passe, j'en suis sûr.

Merci.

Thorsen
la source
Hmm, êtes-vous sûr que c'est correct? ps -eaf | grep [fF] irefox aurait plus de sens. Cela ressemble à une expression régulière et signifie en correspondance de l'un des caractères inclus. Pourrait aussi être utilisé comme plage, par exemple [0-9]
mbs
Hé bien oui. C’était le problème que j’avais: une classe de personnages ne contenant qu’un seul personnage semblait inutile, mais produisant un effet secondaire «mystérieux»! Quoi qu'il en soit, jokerdino a fourni une bonne explication.
Thorsen

Réponses:

57

L'expression entre crochets fait partie du shell bash (et d'autres shells également) du modèle de correspondance de classe de caractères de grep.

Le grepprogramme comprend par défaut les expressions régulières de base POSIX. Avec cela, vous pouvez définir des classes de caractères. Par exemple ps -ef | grep [ab9]irefox, trouverait " un irefox", " b irefox", " 9 irefox" si ceux-ci existaient, mais pas " ab irefox".

La commande grep [a-zA-Z0-9]irefoxtrouverait même tous les processus commençant par une lettre ou un chiffre et se terminant par "irefox".

Alors ps -ef | grep firefoxcherche des lignes avec firefoxdedans. Puisque le processus grep lui-même contient "firefox", grep le trouve également. En ajoutant a [], nous recherchons uniquement la classe de caractères "[f]" (constituée uniquement de la lettre "f" et qui est donc équivalente à un "f" sans les crochets). L'avantage des crochets est maintenant que la chaîne "firefox" n'apparaît plus dans la commande grep. Par conséquent, grep lui-même n'apparaîtra pas dans le résultat de grep.

Comme peu de gens connaissent les crochets comme correspondance de classe de caractères et expressions régulières en général, le deuxième résultat peut paraître un peu mystérieux.

Si vous voulez corriger le deuxième résultat, vous pouvez les utiliser de cette façon:

ps -ef | grep [f]irefox  > data
grep firefox data

(Référence)

jokerdino
la source
1
Hmm. Je ne me suis pas rendu compte que le [] était quelque chose interprété par le shell AVANT que grep ait même une chance. Merci pour l'explication. Toutes les années ont été résolues.
Thorsen
Heureux d'aider. Passez une bonne journée :)
jokerdino
1
Dans bash, les crochets seront passés à grep s'il n'y a pas de correspondance pour le mot dans lequel ils se trouvent (c'est-à-dire qu'aucun fichier nommé "firefox" dans le répertoire en cours). Cependant, grep a aussi des classes de caractères et [f] dans grep est identique à f.
Daniel Hershcovich
6
En fait, dans ce cas, je ne pense pas que cela soit interprété par le shell avant grep. Je pense qu’il [f]s’agit du crochet d’expression régulière utilisé pour les classes de caractères. Comme dans "[a-z0-9] irefox", grep correspondrait également "airefox" et "0irefox". Vous pouvez facilement voir que ce n'est pas une bash intégrée, car elle echo $([f])renvoie une erreur.
con-f-use
4
La raison spécifique qui [f]irefoxfonctionne à cette fin est qu’elle n’est pas développée par le shell. Lorsque le shell se développe [f]irefoxen firefox, cela entraîne la grepvisualisation firefox, et fait ensuite firefoxpartie de grepla chaîne de commande de, exactement comme si elles grep firefoxétaient exécutées. Mais il est bon de garder pattern matching coquille à l' esprit , en particulier lorsque les scripts, parce que s'il y a un fichier appelé firefoxdans le répertoire courant , le shell n'étendre à[f]irefoxfirefox et cette méthode échoue, par exemple, la grepligne de psest affiché.
Eliah Kagan
10

La raison est que la chaîne

grep firefox

correspond au motif firefox, mais la chaîne

grep [f]irefox

ne correspond pas au motif [f]irefox(ce qui est équivalent au motif firefox).

C'est pourquoi le premier grep correspond à sa propre ligne de commande de processus, alors que le second ne le fait pas.

Daniel Hershcovich
la source
Cela me fait encore plus mal à la tête
Pithikos