Warum gibt grep nicht das zurück, was ich erwarte, wenn ich einfache Anführungszeichen verwende?

Warum gibt grep nicht das zurück, was ich erwarte, wenn ich einfache Anführungszeichen verwende?

Ich habe eine Datei mit folgendem Inhalt:

sh-4.2$ cat file1
example of multiple
pattern
this is an
example of multipole
sorry multiple
pattern matching
using grep
so the example is the
file itself
-example
-multiple
-bye
tata
!

Beim Suchen nach „-example“ in der obigen Datei liefert der grep-Befehl nicht die gewünschte Ausgabe. Ich weiß, dass die Option -e verwendet werden sollte, wenn das Muster „-“ enthält:

Im ersten Beispiel habe ich-Beispieldirekt ohne Anführungszeichen:

sh-4.2$ grep -example file1
example of multiple
example of multipole
so the example is the
-example

-Beispielmit einfachen Anführungszeichen:

sh-4.2$ grep '-example' file1
example of multiple
example of multipole
so the example is the
-example

-Beispielmit doppelten Anführungszeichen und Escape-Zeichen

sh-4.2$ grep "\-example" file1
-example
sh-4.2$

Antwort1

Nun, Sie wissen, dass das Suchmuster ein '-' enthält, und Sie wissen, dass Sie das -eFlag verwenden müssen, wenn das Suchmuster ein '-' enthält. Da Sie das Flag nicht verwenden, -einterpretiert die Shell Ihr "Muster" stattdessen als Argument (und Parameter). Sie können das sehen mit:

$ grep "-foo" file1
grep: oo: No such file or directory

Im weiteren Sinne teilt Ihr Code der Shell mit, dass Sie ihn mit dem Argument und einem Parameter „xample“ grep "-example" file1ausführen möchten .grep-e

Dies ist das gleiche Problem, auf das wir stoßen, wenn wir etwas wie versuchen rm -my-silly-file-name– es funktioniert nicht und wir müssen rm ./-my-silly-file-namestattdessen etwas wie verwenden. Eine andere Problemumgehung wäre rm -- -my-silly-file-name. Wir können diese Redewendung hier verwenden:

$ grep -- "-example" < file1
-example

Das "--" teilt der Shell mit, dass alles, was danach kommt,nichtein Argument.

Alternativ können Sie das "-" einfach mit einem "\" maskieren, wie Sie gesehen haben:

grep "\-example" file1

Dieser Artikel geht näher auf das Zitieren ein: der relevante Teil istParameter und Backquoted-Befehle, die von der Shell interpretiert werden sollen, sind in doppelte Anführungszeichen eingeschlossen.Wenn Sie Anführungszeichen verwenden, wird der Inhalt von der Shell interpretiert.

Antwort2

Sie wissen, dass die Option -e verwendet werden sollte, wenn das Muster mit ‚-‘ [beginnt]“, aber Sie verwenden sie nicht, obwohl Sie sie verwenden sollten. grep -e -example file1Dadurch erhalten Sie das erwartete Ergebnis.

Folgendes wird in jedem Ihrer Beispiele tatsächlich ausgeführt:

  • grep -example file1=> grep -e xample file1(-e ist erforderlich)
  • grep '-example' file1=> grep -e xample file1(-e ist erforderlich)
  • grep "\-example" file1=> grep \-example file1(-e ist nicht notwendig)

Antwort3

Ein Argument, das mit beginnt, -wird als Option betrachtet.

In Ihren ersten beiden Fällen grepist das erste an übergebene Argument -example, das grepals -e xample( xampleArgument für die -eOption, suchen Sie also nach xample) verstanden wird.

Im dritten Fall \-examplewird an übergeben grep. Da es nicht mit beginnt -, wird es nicht als Option verwendet. Stattdessen wird es als regulärer Ausdruck verwendet. Das Verhalten für \-ist jedoch gemäß POSIX nicht spezifiziert, sodass Sie keine Garantie dafür haben, was es abgleicht. Bei den meisten grepImplementierungen \-wird ein übereinstimmen -, Sie können sich jedoch grepImplementierungen vorstellen, bei denen \-ein spezieller Operator sein kann (siehe beispielsweise GNU, grepwo \+ein spezieller Operator ist und nicht mit einem wörtlichen übereinstimmt +).

Wenn Sie -examplenicht als Option berücksichtigt werden möchten, müssen Sie entweder:

  • grep -- -example file. Das --markiert das Ende der Optionen. Alles danach ist keine Option (also das erste Argument das zu suchende Muster und der Rest die Liste der zu durchsuchenden Dateien).
  • grep -e -example file. Hier -examplewird als Argument für die -eOption genommen.

Aus diesem Grund sollten Sie sich das Schreiben angewöhnen:

grep -e "$pattern" file

Oder

grep -- "$pattern" file

wenn Sie nicht garantieren können, $patterndass es nicht damit beginnt -.

Beachten Sie, dass Sie es hier auch schreiben könnten:

grep '[-]example' file

Obwohl sehenKlammerausdruck (ohne Bereiche), der mit unerwartetem Zeichen in Bash übereinstimmtüber mögliche Komplikationen bei diesem Ansatz.

verwandte Informationen