
Ich wollte alle TXT-Dateien mit dem Platzhalterzeichen „*“ durchsuchen.
Ich habe diesen Befehl (auch ohne Anführungszeichen „“) ausprobiert, aber er hat nicht funktioniert.
ls | grep "*.txt"
Das Interessante ist, dass es funktioniert, wenn ich im Grep-Befehl ein anderes Zeichen einfüge, das einer TXT-Datei im Verzeichnis entspricht.
>>ls | grep s*.txt
sample.txt
Ich weiß, dass das ls *.txt
funktionieren wird, aber ich war etwas überrascht über die Art des Grep-Befehls. Kann mir jemand helfen, warum das passiert?
Liegt es daran, dass grep reguläre Ausdrücke verwendet? Bitte helfen Sie.
Antwort1
In regulären Ausdrücken *
bedeutet „eine beliebige Anzahl des vorherigen Elements“, nicht „eine beliebige Anzahl beliebiger Zeichen“, wie es in Shell-Mustern der Fall ist. Und .
bedeutet „jedes einzelne Zeichen“. Um also nach „irgendetwas, gefolgt von einem wörtlichen .txt
„“ zu suchen, würden Sie verwenden .*\.txt
. Oder einfach \.txt
, da reguläre Ausdrücke normalerweise überall in der Zeile nach der Übereinstimmung suchen. Dann \.txt
würde auch wieder ein Dateiname wie übereinstimmen foo.txtgz
, da das .txt
nicht am Ende stehen müsste. Sie müssten \.txt$
das Muster am Zeilenende sperren.
Der reguläre Ausdruck *.txt
ist entweder bedeutungslos, ein Fehler oder sucht nach einem wörtlichen Asterisk, abhängig von der Implementierung und davon, ob Sie einfache reguläre Ausdrücke ( grep
) oder erweiterte reguläre Ausdrücke ( grep -E
) verwenden. Verwenden Sie ihn am besten nicht.
Andererseits s*.txt
würde nach „beliebige Anzahl von Buchstaben s
, dann ein beliebiges einzelnes Zeichen, dann Literal txt
“ gesucht. Das ist ein gültigerer regulärer Ausdruck, aber … stimmt trotzdem nicht mit überein sample.txt
.
Stattdessen passiert in Ihrem zweiten Befehl Folgendes: Da s*.txt
es nicht in Anführungszeichen steht, erweitert die Shell das , s*.txt
bevor grep
es angezeigt wird. Wenn die einzige passende Datei ist sample.txt
, grep
sucht es in der Ausgabe von danach ls
. (Wenn es mehrere passende Dateinamen gäbe, würde der erste als Muster und der Rest als zu grep
lesende Dateinamen verwendet. In diesem Fall würde die Eingabe aus der Pipe ignoriert.)
Aber, ls
kann eine Liste von Dateien auch nehmen, so während Sie verwenden könnten
ls | grep '\.txt'
Um eine Datei abzurufen .txt
, wäre es wahrscheinlich einfacher, einfach
ls *.txt
stattdessen.
Antwort2
Das liegt zum Teil daran, dass grep
reguläre Ausdrücke verwendet werden (tatsächlich re
steht das im Namen dafür - es ist die Abkürzung fürGlobalRregelmäßigtAusdruckPDruck).
Das *
Platzhalterzeichen in regulären Ausdrücken unterscheidet sich vom *
Platzhalterzeichen beim Shell-Globbing.
In regulären Ausdrücken *
bedeutet "null oder mehr des zuvor definierten Objekts". Allerdings .
istAuchein Platzhalter, der „ein Zeichen“ bedeutet.
Bedeutet in Shell-Globs *
„null oder mehr Zeichen“. .
ist überhaupt kein Platzhalter.
Wenn Sie grep
nach dem Muster suchen "*.txt"
, suchen Sie nach null oder mehr von irgendetwas, gefolgt von genau einem weiteren Zeichen, gefolgt von der Literalzeichenfolge txt
.
Wenn Sie grep
für das Muster "s*.txt"m you are looking for a literal
s , followed by zero or more
s s, followed by any character, followed by the literal string
txt`.
Aus diesem Grund finden Sie in regulären Ausdrücken häufig das .*
, was „ein beliebiges Zeichen gefolgt von null oder mehr beliebigen Zeichen“ bedeutet. Regex für „buchstäblich jede beliebige Zeichenkombination außer null Zeichen“.
Wenn Sie ls *.txt
der Shell sagen: „Suchen Sie nach allen Dateinamen, die dem Glob-Muster entsprechen *.txt
, listen Sie sie hier auf und geben Sie sie als Argumente für den ls
Befehl an.“
Antwort3
Bitte beachten Sie, dass grep die Datei durchsuchtInhaltwobei das erste Argument das Suchmuster ist und die anderen Argumente als zu untersuchende DATEIEN interpretiert werden
es wird Ihnen klarer, wenn Sie grep -H -o
Flags verwenden oder Ihre grep
in ein Skript einfügen und es ausführen, bash -x script
um zu sehen, wie Shell-Globs erweitert werden, bevor sie als Argumente übergeben werden