Groß- und Kleinschreibung nicht berücksichtigen und durch sed ersetzen

81

Ich versuche, mit SED Text aus einer Protokolldatei zu extrahieren. Ich kann ohne allzu große Probleme suchen und ersetzen:

sed 's/foo/bar/' mylog.txt

Ich möchte jedoch die Suche unabhängig von Groß- und Kleinschreibung machen. Nach dem, was ich gegoogelt habe, sollte das Anhängen ian das Ende des Befehls funktionieren:

sed 's/foo/bar/i' mylog.txt

Dies gibt mir jedoch eine Fehlermeldung:

sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'

Was läuft hier falsch und wie behebe ich das?

Craig Walker
quelle
2
Können Sie versuchen, Ihre Kopie von sed zu aktualisieren? Iist eine GNU-Erweiterung, die mit Ihrer Kopie von sed möglicherweise nicht verfügbar ist.
Lazer
4
BEARBEITEN : Ich habe die OS X-Qualifikation durchlaufen, als das OP eine Antwort akzeptierte, die unter OS X nicht funktioniert. (Wie eine andere Antwort andeutete, unterstützt sed unter OS X im Gegensatz zur Apple-Dokumentation kein Matching ohne Berücksichtigung der Groß- und Kleinschreibung.)
Danorton
1
@ Danorton: Danke dafür; Falls Sie das Gefühl abgeleitet haben, dass die Apple-Dokumentation etwas verspricht, das die Implementierung nicht aus meiner Antwort unten liefert: man sedIst mit der Implementierung konsistent - keine Erwähnung (und in der Praxis keine Unterstützung) für Matching ohne Berücksichtigung der Groß- und Kleinschreibung; Wenn Sie eine Dokumentation gefunden haben, die etwas anderes behauptet, teilen Sie uns dies bitte mit.
mklement0
1
@ mklement0, ja, sorry, ich stehe korrigiert. In der Apple-Dokumentation wird kein Anspruch auf Matching ohne Berücksichtigung der Groß- und Kleinschreibung für sed erhoben.
Danorton
1
FWIW, die GNU-Versionen der Tools, deren BSD-Version mit OS X geliefert wird, sind bei verschiedenen Paketmanagern erhältlich. Ich habe die vollständige Suite von Textdienstprogrammen über Homebrew mit einem gPräfix installiert , damit ich sie verwenden kann gsedoder gdatewenn ich eine Funktion benötige, die in der Standardversion nicht enthalten ist.
Mark Reed

Antworten:

72

Um es klar auszudrücken : Unter macOS - ab Mojave (10.14) - sed- was die BSD- Implementierung ist - wird das Matching ohne Berücksichtigung der Groß- und Kleinschreibung NICHT unterstützt - kaum zu glauben, aber wahr. Die zuvor akzeptierte Antwort , die selbst einen GNU- sed Befehl anzeigt , erhielt diesen Status aufgrund der perlin den Kommentaren erwähnten basierenden Lösung.

Verwenden Sie Folgendes, damit diese Perl-Lösung auch mit Fremdzeichen über UTF-8 funktioniert :

perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
  • -C Aktiviert die UTF-8-Unterstützung für Streams und Dateien, vorausgesetzt, das aktuelle Gebietsschema basiert auf UTF-8.
  • -Mutf8weist Perl an, den Quellcode als UTF-8 zu interpretieren (in diesem Fall die übergebene Zeichenfolge -pe) - dies ist das kürzere Äquivalent des ausführlicheren -e 'use utf8;'.Dankes, Mark Reed

(Beachten Sie, dass die Verwendung ebenfalls awkkeine Option ist , da awkunter macOS (dh BWK awk , auch bekannt als BSD awk ) die Gebietsschemas anscheinend überhaupt nicht bekannt sind - seine tolower()und toupper()Funktionen ignorieren Fremdzeichen (und sub()/ oder gsub()haben keine Groß- / Kleinschreibung-Flags) anfangen mit).)

mklement0
quelle
So korrigieren Sie das
Eduardo Cuomo
69

Anmerkung des Herausgebers : Diese Lösung funktioniert nicht unter macOS (sofort einsatzbereit), da sie nur für GNU gilt sed , während macOS mit BSD geliefert wird sed.

Großschreibe das Ich.

sed 's/foo/bar/I' file
Wesley Rice
quelle
2
Ich habe das auch gesehen und versucht ... aber ich bekomme immer noch die gleiche Fehlermeldung.
Craig Walker
15
BSD sed hat anscheinend viele Einschränkungen. Ich würde dies in PERL tun (dh perl -pe 's / foo / bar / i'), wenn das der Fall ist.
Wesley Rice
3
Die Standardinstallation von OS X Lion gibt den Fehler aus: sed: 1: "s / foo / bar / I": fehlerhaftes Flag im Ersatzbefehl: 'I'
Ben Clayton
13
Das ISuffix ist keine tragbare Verwendung von sed. POSIX sedverwendet nur Basic Regular Expressions (BREs), die überraschend begrenzt sind. Sie unterstützen nicht einmal das +(Sie müssen \{1,\}stattdessen verwenden), geschweige denn das Matching ohne Berücksichtigung der Groß- und Kleinschreibung. Die einzige tragbare Möglichkeit, dies mit sed zu tun, besteht darin, nach etwas Ähnlichem /[hH][eE][lL][lL][oO]/zu suchen, was oft unpraktisch sein wird.
Edam
5
Das muss auch so sein, /gIdass es nur beim ersten Spiel funktioniert.
Faheem Mitha
25

Eine weitere Lösung für sedMac OS X besteht darin, gsedMacPorts oder HomeBrew zu installieren und anschließend den Alias ​​zu erstellen sed='gsed'.

Casimir Kristall
quelle
gsed "s / a / b / Ig" funktioniert, danke! Warum sollte eine gute Antwort eine negative Bewertung erhalten?
Matthias M
3
Diese Antwort ist großartig. verwendet brew install gnu-sedging dann zu meinem ~ / .bash_profile und fügte den Alias ​​hinzu. Danke @davmat
ThinkBonobo
8
Besser brew install gnu-sed --with-default-names- dies überschreibt die Standardeinstellung sed.
März
4

Die sed FAQ befasst sich mit der eng verwandten Suche ohne Berücksichtigung der Groß- und Kleinschreibung . Es wird darauf hingewiesen, dass a) viele Versionen von sed eine Flagge dafür unterstützen und b) es in sed umständlich ist, lieber awk oder Perl zu verwenden.

Um dies in POSIX sed zu tun, schlagen sie drei Optionen vor (hier für die Substitution angepasst):

  1. In Großbuchstaben konvertieren und ursprüngliche Zeile im Haltebereich speichern; Dies funktioniert jedoch nicht für Ersetzungen, da der ursprüngliche Inhalt vor dem Drucken wiederhergestellt wird. Daher eignet es sich nur zum Einfügen oder Hinzufügen von Zeilen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird.

  2. Vielleicht sind die Möglichkeiten beschränkt zu sein FOO, Foound foo. Diese können abgedeckt werden durch

    s/FOO/bar/;s/[Ff]oo/bar/
    
  3. Um nach allen möglichen Übereinstimmungen zu suchen, kann man für jedes Zeichen Klammerausdrücke verwenden:

    s/[Ff][Oo][Oo]/bar/
    
Benjamin W.
quelle
1

Die Mac-Version von sedscheint etwas eingeschränkt zu sein. Eine Möglichkeit, dies zu umgehen, besteht darin, einen Linux-Container (über Docker) zu verwenden, der eine verwendbare Version von sed:

cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'
user1307434
quelle
15
Dies ist eine besonders abscheuliche Sache. Wenn jemand dies ernsthaft in Betracht zieht, installieren Sie einfach eine GNU sed lokal.
ocodo
Overkill aber nützlicher allgemeiner Ansatz zu wissen!
YvesgereY
1

Wenn Sie zuerst einen Mustervergleich durchführen, z.

/pattern/s/xx/yy/g

dann möchten Sie das Inach dem Muster setzen:

/pattern/Is/xx/yy/g

Beispiel:

echo Fred | sed '/fred/Is//willma/g'

kehrt zurück willma; ohne das Igibt es den String unberührt zurück ( Fred).

CBB
quelle
2
Auf MacOs bekomme ich:sed: 1: "/fred/Is//willma/g": invalid command code I
Chris F Carroll
Guter Tipp. So verwende ich es bei einer komplexen Suche : sed -r '/'"$PATTERN"'/I,${s//'$YELLOW'&'$NO_COLOR'/g;b};$q3'. Der Text wird gedruckt, und wenn ein Muster (ohne Berücksichtigung der Groß- und Kleinschreibung) gefunden wurde, wird der Text in Gelb (Ansi-Farbe) hervorgehoben. Wenn nicht gefunden - gibt den Exit-Code 3 zurück.
Noam Manos
0

Ich hatte ein ähnliches Bedürfnis und kam auf folgendes:

Dieser Befehl, um einfach alle Dateien zu finden:

grep -i -l -r foo ./* 

Um this_shell.sh auszuschließen (falls Sie den Befehl in ein Skript namens this_shell.sh einfügen ), senden Sie die Ausgabe an die Konsole, um zu sehen, was passiert ist, und verwenden Sie dann sed für jeden gefundenen Dateinamen, um den Text foo durch bar zu ersetzen ::

grep -i -l -r --exclude "this_shell.sh" foo ./* | tee  /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done 

Ich habe mich für diese Methode entschieden, da mir nicht gefallen hat, dass alle Zeitstempel für nicht geänderte Dateien geändert wurden. Wenn Sie das grep-Ergebnis eingeben, können nur die Dateien mit dem Zieltext angezeigt werden (dies kann wahrscheinlich auch die Leistung / Geschwindigkeit verbessern).

Stellen Sie sicher, dass Sie Ihre Dateien sichern und testen, bevor Sie sie verwenden. Funktioniert in einigen Umgebungen möglicherweise nicht für Dateien mit eingebetteten Leerzeichen. (?)

gojimmypi
quelle
0

Verwenden Sie Folgendes, um alle Vorkommen zu ersetzen: sed 's / foo / bar / gI' mylog.txt

yogendrar54
quelle
Siehe stackoverflow.com/a/4412964/4294399 , das die Hauptstadt abdeckt I. Ich denke auch nicht, dass dies die Frage wirklich beantwortet, da es nicht um globalen Ersatz geht.
Calculuswhiz