Probleme mit regulären Ausdrücken in Bash: [^ negate] scheint nicht zu funktionieren

8

Wenn ich ls /directory | grep '[^term]'in Bash ausführe, erhalte ich eine regelmäßige Auflistung, als würde der grepBefehl irgendwie ignoriert. Ich habe das Gleiche mit egrepversucht, ich habe versucht, es mit doppelten und einfachen Anführungszeichen zu verwenden, aber zu keinen besseren Ergebnissen. Wenn ich es versuche, ls /directory | grep '^[term]bekomme ich alle Einträge, die mit term beginnen - wie erwartet.

Ich habe diesen Befehl in einem Online-Editor ausprobiert, in dem ich meinen regulären Ausdruck testen kann , und er hat so funktioniert, wie er sollte. Aber nicht in Bash. Es funktioniert also in einer Simulation, aber nicht im wirklichen Leben.

Ich arbeite an Crunchbang Linux 10. Ich hoffe, dass dies genug Informationen sind und freue mich auf jeden Hinweis, denn es ist wirklich frustrierend, nicht auf einer so grundlegenden Ebene auszuführen und Stunden Zeit zu verschwenden!

erch
quelle
Ich bin verwirrt wegen des Negats im Titel. Möchten Sie grepZeilen beginnen mit Begriff. Oder möchten Sie nach Zeilen suchen, die überhaupt keinen Begriff enthalten?
Bernhard
@Bernhard: Ich möchte eine Auflistung ohne den Begriff in den eckigen Klammern. Es muss nicht genau "Begriff" sein! Soweit ich es verstanden habe, bedeutet [^ abc], dass alles, was a, b oder c oder eine Kombination davon enthält, nicht in der Liste enthalten sein sollte.
Erch

Antworten:

12

Sind Sie sicher, dass das, was Sie wollen, passiert? Wenn Sie rennen ls /directory | grep '[^term]', suchen Sie im Wesentlichen nicht nach den Buchstaben ter m. Das heißt, wenn eine Datei andere Buchstaben im Namen hat, wird sie weiterhin in der Ausgabe von angezeigt ls. Nehmen Sie zum Beispiel das folgende Verzeichnis:

$ ls
alpha  brave  bravo  charlie  delta

Wenn ich jetzt renne, ls |grep '^[brav]'bekomme ich folgendes:

$ ls |grep '^[brav]'
alpha
brave
bravo

Wie Sie sehen können, nicht nur ich braveund bravoich habe auch , alphaweil die Zeichenklasse []jeden Buchstaben aus dieser Liste erhalten.

Wenn ich folge ls |grep '[^brav]', bekomme ich folglich alle Dateien, die die Zeichen brav irgendwo im Namen enthalten.

$ ls |grep '[^brav]'
alpha
bravo
brave
charlie
delta

Wenn Sie bemerken, dass es die gesamte Verzeichnisliste enthält, weil alle Dateien mindestens einen Buchstaben hatten, der nicht in der Zeichenklasse enthalten war.

Also, wie Kanvuanza sagte, um nach der Umkehrung von "Begriff" zu suchen, im Gegensatz zu den Zeichen, die t e r mSie verwenden sollten grep -v.

Zum Beispiel:

$ ls |grep -v 'brav'
alpha
charlie
delta

Auch wenn Sie nicht möchten, dass Dateien mit Zeichen in der Klasse verwendet werden grep -v '[term]'. Dadurch wird verhindert, dass Dateien mit einem dieser Zeichen angezeigt werden. (Kanvuanzas Antwort)

Zum Beispiel:

$ ls |grep -v '[brav]'

Wie Sie sehen, wurden keine Dateien aufgelistet, da alle Dateien in diesem Verzeichnis mindestens einen Buchstaben aus dieser Klasse enthielten.

Nachtrag:

Ich wollte hinzufügen, dass es mit PCRE möglich ist, nur Regex zu verwenden, um mit negativen Ausdrücken herauszufiltern. Um dies zu tun, würden Sie etwas verwenden, das als negative Vorausschau-Regex bekannt ist : (?!<regex>).

Mit dem obigen Beispiel können Sie so etwas tun, um die gewünschten Ergebnisse zu erzielen, ohne grepFlags zu verwenden.

$ ls | grep -P '^(?!brav)'
alpha
charlie
delta

Um diesen regulären Ausdruck zu dekonstruieren, stimmt er zuerst am Anfang einer Zeile ^überein und sucht dann nach Zeichenfolgen, die nicht übereinstimmen brav, um anschließend zu folgen. Nur alpha,, charlieund deltaübereinstimmen, damit nur diese gedruckt werden.

prateek61
quelle
1
Das heißt, wenn eine Datei andere Buchstaben im Namen hat, wird sie weiterhin in der Ausgabe von ls angezeigt. Dies beantwortet einige Fragen! :) Der beste Weg für den Moment scheint also die -vOption zu sein. Danke für deine Unterstützung! Diese Frage hat meinen Nachmittag wirklich ruiniert, wo Ihre Antwort meinen Abend erhellt!
Erch
+1 für negative look-ahead regex.
Abhishek Kashyap
3

Ich denke, diese grep -vFlagge macht, was Sie wollen. Von der Manpage :

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.

Sie können ls /directory | grep -v [term]damit nicht übereinstimmende Zeilen drucken.

Pedro Lacerda
quelle
Ich bin mir dieser Option bewusst, aber irre ich mich, wenn ich annehme, dass [^ xyz] das Gegenteil von [xyz] ist und auf jeden Fall funktionieren sollte? Ich möchte auch vermeiden, Einstellungen irgendwo auf einer solchen Grundebene zu bearbeiten. Die Verwendung einer invertierenden Option und / oder der Bearbeitung von Einstellungen ist sicher ein guter Weg, aber soweit ich es verstanden habe, sollte dies sofort funktionieren.
Erch
Ich denke, Sie haben Recht, das ist die übliche Notation für Klassenverneinung (dh ... [^abc]Aber ich bin mir ziemlich sicher, dass grep keine Klassenverneinungen unterstützt, außer ein paar Standardnegationen (z. B. [[:^digits:]]). Grep-Unterstützung für Verneinung ist schrecklich !
Pedro Lacerda
Grep Unterstützung für die Verneinung ist schrecklich! Und das sind die Hinweise, die das wahre Sahnehäubchen sind. Ich habe die gleichen Probleme mit egrep und bin im Moment weit davon entfernt, [zumindest für mich scheinbar] fortgeschrittenere Befehle zu verwenden. Können Sie einen Befehl vorschlagen, der bessere Ergebnisse und weniger Kopfschmerzen liefert?
Erch
@ cellar.dweller, grepder Umgang mit Zeichenklassen ist in Ordnung. Es bedeutet nur etwas ganz anderes als das, was Sie (falsch) verstehen. [abc]bedeutet einen von a, b, oder c; [^abc]bedeutet alles andere als das oben genannte. Es ist ein Charakter.
vonbrand
@ cellar.dweller: Ich denke, Ihr größtes Problem ist ein Missverständnis von Regex, insbesondere von Charakterklassen innerhalb von Regex.
Tink