Wie funktioniert dieser klapprige Klammerausdruck in grep?

38

Ich habe diesen Einzeiler kürzlich gesehen:

$ ps -ef | grep [f]irefox 

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

Es scheint also die Liste der Prozesse mit "firefox" in den Daten zurückzugeben, aber den grep-Prozess selbst wegzulassen, und entspricht daher in etwa:

ps -ef |grep -v grep| grep firefox

Ich kann jedoch nicht verstehen, wie es funktioniert. Ich habe die Manpage auf grep und anderswo durchgesehen, aber keine Erklärung gefunden.

Und um das Rätsel zu verschärfen, wenn ich laufe:

$ 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 ....

der [t] rick scheint nicht mehr zu funktionieren!

Jemand hier wird wissen, was los ist, da bin ich mir sicher.

Vielen Dank.

Thorsen
quelle
Hmm, bist du sicher, dass das richtig ist? ps -eaf | grep [fF] irefox wäre sinnvoller. Dies sieht aus wie ein regulärer Ausdruck und entspricht im Mittel einem der eingeschlossenen Zeichen. Könnte auch als Range gemacht werden, zB [0-9]
mbs
Nun ja. Das war das Problem, das ich hatte: Eine Charakterklasse, die nur einen Charakter enthielt, schien sinnlos, erzeugte aber einen "mysteriösen" Nebeneffekt! Trotzdem hat jokerdino eine gute Erklärung geliefert.
Thorsen

Antworten:

57

Der eckige Klammerausdruck ist Teil der Zeichenklassen-Musterübereinstimmung von grep in der Bash-Shell (und auch in anderen Shells) .

Das grepProgramm versteht standardmäßig grundlegende reguläre POSIX-Ausdrücke. Damit können Sie Zeichenklassen definieren. Zum Beispiel ps -ef | grep [ab9]irefoxwürde " a irefox", " b irefox", " 9 irefox" finden, wenn diese existieren, aber nicht " ab irefox".

Der Befehl findet grep [a-zA-Z0-9]irefoxsogar alle Prozesse, die mit genau einem Buchstaben oder einer Ziffer beginnen und mit "irefox" enden.

Also ps -ef | grep firefoxsucht nach Zeilen mit firefoxdrin. Da der Grep-Prozess selbst "Firefox" enthält, findet Grep das auch. Durch Hinzufügen von a []wird nur die Zeichenklasse "[f]" gesucht (die nur aus dem Buchstaben "f" besteht und daher nur einem "f" ohne eckige Klammern entspricht). Der Vorteil der Klammern ist nun, dass der String "firefox" im grep-Befehl nicht mehr erscheint. Daher wird grep selbst nicht im grep-Ergebnis angezeigt.

Da nicht sehr viele Leute mit eckigen Klammern als Zeichenklassenvergleich und regulären Ausdrücken im Allgemeinen vertraut sind, könnte das zweite Ergebnis etwas mysteriös aussehen.

Wenn Sie das zweite Ergebnis korrigieren möchten, können Sie diese folgendermaßen verwenden:

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

(Referenz)

jokerdino
quelle
1
Hmm. Mir ist nicht in den Sinn gekommen, dass das [] von der Shell interpretiert wurde, BEVOR grep überhaupt eine Chance bekommen würde. Danke für die Erklärung. Alle [m] yterien wurden aufgelöst.
Thorsen
Freue mich zu helfen. Einen schönen Tag noch :)
jokerdino
1
In bash, die eckigen Klammern werden übergeben werden grep , wenn es keine Übereinstimmung für das Wort ist , sie sind in (dh keine Datei mit dem Namen „Firefox“ im aktuellen Verzeichnis). Grep hat jedoch auch Zeichenklassen und [f] in grep ist genau das gleiche wie f.
Daniel Hershcovich
6
Eigentlich glaube ich in diesem Fall nicht, dass es von der Shell vor grep interpretiert wird. Ich denke, es [f]ist die Klammer für den Mustervergleich mit regulären Ausdrücken für Zeichenklassen. Wie in "[a-z0-9] irefox" würde grep auch mit "airefox" und "0irefox" übereinstimmen. Sie können leicht erkennen, dass es sich nicht um eine integrierte Bash handelt, da echo $([f])ein Fehler zurückgegeben wird.
con-f-use
4
Der spezielle Grund [f]irefoxdafür ist, dass es nicht von der Shell erweitert wird. Wenn die Schale expandiert [f]irefoxzu firefox, dass Ursachen grepzu sehen firefox, und dann firefoxTeil ist grep‚s Befehlsfolge, genau als ob grep firefoxwurden durchgeführt. Es empfiehlt sich jedoch, den Shell-Pattern-Abgleich im Auge zu behalten , insbesondere bei der Skripterstellung. Wenn firefoxim aktuellen Verzeichnis eine Datei aufgerufen wird , wird die Shell auf erweitert [f]irefox,firefox und diese Methode schlägt fehl, dh die grepZeile von pswird angezeigt.
Eliah Kagan
10

Der Grund ist, dass die Zeichenfolge

grep firefox

stimmt mit dem Muster überein firefox, aber mit der Zeichenfolge

grep [f]irefox

stimmt nicht mit dem Muster überein [f]irefox(was dem Muster entspricht firefox).

Das ist der Grund, warum das erste grep mit seiner eigenen Prozessbefehlszeile übereinstimmt, das zweite grep nicht.

Daniel Hershcovich
quelle
Dies macht meinen Kopf noch mehr weh
Pithikos