sed
BSD / macOS Sed vs. GNU Sed vs. POSIX Sed-Spezifikation
Suche…
Einführung
So zitieren Sie aus der @ @ SnoringFrog-Anfrage zur Erstellung eines Themas:
"Einer der größten Sprüche, die sed verwenden, ist Skripts, die fehlschlagen (oder auf unerwartete Weise erfolgreich sind), weil sie für den einen und nicht für den anderen geschrieben wurden. Ein einfaches Herunterfahren der größeren Unterschiede wäre gut."
Bemerkungen
macOS verwendet die BSD- Version von sed [1] , die sich in vieler Hinsicht von der in Linux- Distributionen enthaltenen GNU- sed Version unterscheidet.
Ihr gemeinsamer Nenner ist die Funktionalität von POSIX verordnet: siehe die POSIX sed spec.
Der tragbarste Ansatz besteht darin , nur POSIX-Funktionen zu verwenden , was jedoch die Funktionalität einschränkt :
Insbesondere legt POSIX nur die Unterstützung für reguläre Basisausdrücke fest , für die viele Einschränkungen gelten (z. B. keine Unterstützung für
|(Alternative), keine direkte Unterstützung für+und?) Und unterschiedliche Fluchtanforderungen.- Caveat: GNU
sed(ohne-r), tut Unterstützung\|,\+und\?, das NICHT POSIX-kompatibel ist; Verwenden Sie--posixzum Deaktivieren (siehe unten).
- Caveat: GNU
So verwenden Sie nur POSIX-Funktionen :
(beide Versionen): Verwenden Sie nur die Optionen
-nund-e(verwenden Sie nicht-Eoder-r, um die Unterstützung für erweiterte reguläre Ausdrücke zu-E)GNU
sed: add Option--posixPOSIX-only - Funktionalität zu gewährleisten (Sie brauchen nicht unbedingt das, aber ohne sie könnten Sie versehentlich nicht-POSIX - Funktionen ohne Bemerken am Ende mit; Einschränkung:--posixselbst ist nicht POSIX-konform )Die Verwendung von ausschließlich POSIX-Funktionen bedeutet strengere Formatierungsanforderungen (da auf viele in GNU
sedverfügbare Funktionen verzichtet wird):- Steuerzeichenfolgen wie
\nund\twerden im Allgemeinen NICHT unterstützt. - Beschriftungen und Verzweigungsbefehle (z. B.
b) müssen über eine separate Option-emit einer tatsächlichen Zeilenvorschubzeile oder einer Fortsetzung fortgesetzt werden. - Details finden Sie unten.
- Steuerzeichenfolgen wie
Beide Versionen implementieren jedoch Erweiterungen des POSIX-Standards:
- Welche Erweiterungen sie implementieren, unterscheidet sich (GNU
sedimplementiert mehr). - selbst die Erweiterungen, die beide implementieren, unterscheiden sich teilweise in der Syntax .
Wenn Sie BEIDE Plattformen unterstützen müssen (Diskussion der Unterschiede):
Inkompatible Funktionen:
Die Verwendung der Option
-iohne Argument (direkte Aktualisierung ohne Sicherung) ist nicht kompatibel:- BSD
sed: MUSS-i '' - GNU
sed: MUSS nur-i(Äquivalent:-i'') verwenden --i ''funktioniert NICHT.
- BSD
-isinnvollerweise die Zeilennummerierung pro Eingabedatei in GNUsedund den letzten Versionen von BSDsed(z. B. unter FreeBSD 10), jedoch nicht unter macOS ab 10.12 .
Beachten Sie, dass, wenn keine-ialle Versionsnummernzeilen kumulativ für die Eingabedateien gelten.Wenn die letzte Eingangsleitung nicht über eine nacheilenden Neuen - Zeile (und wird gedruckt):
- BSD
sed: Hängt bei der Ausgabe immer eine neue Zeile an, auch wenn die Eingabezeile nicht auf einer endet. - GNU
sed: behält den Status der nachlaufenden Newline-Zeile bei , dh sie hängt eine Newline-Zeile nur an, wenn die Eingabezeile auf einer endete.
- BSD
Gemeinsame Merkmale:
- Wenn Sie Ihre
sedSkripte auf das beschränken, was BSDsedunterstützt, funktionieren siesedauch in GNUsed- mit der bemerkenswerten Ausnahme, dass plattformspezifische erweiterte Regex-Funktionen mit-E. Natürlich verzichten Sie auch auf Erweiterungen, die für die GNU-Version spezifisch sind. Siehe nächster Abschnitt.
- Wenn Sie Ihre
Richtlinien für die plattformübergreifende Unterstützung (OS X / BSD, Linux), die sich an den strengeren Anforderungen der BSD-Version orientieren :
Beachten Sie, dass die Abkürzungen macOS und Linux im Folgenden gelegentlich verwendet werden, um sich auf die BSD- bzw. GNU-Versionen von sed zu beziehen, da sie auf jeder Plattform die Standardversionen sind. Es ist jedoch möglich, GNU sed auf macOS zu installieren, beispielsweise mit Homebrew with brew install gnu-sed .
Anmerkung : Wenn die Flags -r und -E nicht verwendet werden ( erweiterte reguläre Ausdrücke), gelten die folgenden Anweisungen für das Schreiben von POSIX-kompatiblen sed Skripten.
Um die POSIX-Konformität zu gewährleisten , müssen Sie sich auf POSIX-BREs ( Basic Regular Expressions) beschränken , die leider, wie der Name schon sagt, recht einfach sind.
Vorbehalt : Nehmen Sie nicht an, dass\|,\+und\?werden unterstützt: GNUsedunterstützt sie (sofern nicht--posixverwendet wird), BSDsedjedoch nicht - diese Funktionen sind nicht POSIX-kompatibel.
Während\+und\?kann auf POSIX-konforme Weise emuliert werden :
\{1,\}für\+,
\{0,1\}für\?.
\|(alternativ) kann leider nicht.Verwenden Sie für leistungsfähigere reguläre Ausdrücke
-E(anstelle von-r), um EREs ( erweiterte reguläre Ausdrücke) zu unterstützen (GNUseddokumentiert-E, aber es funktioniert dort als Alias von-r; neuere Version von BSDsed, wie auf FreeBSD 10, unterstützt jetzt auch-r, die MacOS-Version ab 10.12 jedoch nicht ).
Einschränkung : Auch wenn die Verwendung von-r/-Ebedeutet, dass Ihr Befehl definitionsgemäß nicht POSIX-kompatibel ist, müssen Sie sich dennoch auf POSIX-EREs (erweiterte reguläre Ausdrücke) beschränken . Leider bedeutet dies, dass Sie nicht mehrere nützliche Konstrukte verwenden können, insbesondere:- wortbegrenzte Zusicherungen, da sie plattformspezifisch sind (z. B.
\<unter Linux,[[:<]]unter OS X). - Rückverweise innerhalb regulärer Ausdrücke (im Gegensatz zu den "Rückverweisen" für Capture-Group-Übereinstimmungen in der Ersetzungszeichenfolge von
sFunktionsaufrufen), da BSDsedsie nicht in erweiterten Regex unterstützt (aber seltsamerweise in grundlegende , wo sie POSIX-mandatiert sind).
- wortbegrenzte Zusicherungen, da sie plattformspezifisch sind (z. B.
Steuerzeichen-Escape-Sequenzen wie
\nund\t:Nehmen Sie in Regex (sowohl in Mustern für die Zeilenauswahl als auch im ersten Argument für die
sFunktion) an, dass nur\nals Escape-Sequenz erkannt wird (selten verwendet, da der Musterraum normalerweise eine einzige Zeile ist (ohne\nzu beenden). aber nicht innerhalb einer Zeichenklasse , so dass zB[^\n]nicht funktioniert (wenn Ihre Eingabe keine Steuerzeichen enthält. Außer\tkönnen Sie[^\n]mit[[:print:][:blank:]][^\n]emulieren.[[:print:][:blank:]]; andernfalls Steuerzeichen von Splices als Literale [2] ) - enthalten Steuerzeichen normalerweise als Literale , entweder über gespleißte ANSI-C-Anführungszeichenfolgen (z. B.$'\t') in Shells, die dies unterstützen (bash,ksh,zsh) oder über Befehlssubstitutionen mitprintf(z. B."$(printf '\t')") .- Nur Linux:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b' - OSX und Linux:
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
- Nur Linux:
In Ersetzungszeichenfolgen, die mit dem Befehl
s, wird davon ausgegangen, dass KEINE Steuerzeichen-Escape-Sequenzen unterstützt werden , also auch Steuerzeichen. als Literale wie oben.- Nur Linux:
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b' - macOS und Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Nur Linux:
Gleiches gilt für die Textargumente zu den Funktionen
iunda: Verwenden Sie keine Steuerzeichenfolgen - siehe unten.
Beschriftungen und Verzweigungen : Beschriftungen sowie das Argument mit dem Benennungsnamen für die Funktionen
bundtmüssen entweder von einem wörtlichen Zeilenumbruch oder einem gespleißten$'\n'gefolgt werden . Verwenden Sie alternativ mehrere-eOptionen und beenden Sie jede direkt nach dem Labelnamen.- Nur Linux:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a' - macOS und Linux:
- EITHER (aktuelle Zeilenumbrüche):
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb' - ODER (in
$\nInstanzen zusammengefügt):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb' - ODER (mehrere
-eOptionen):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- EITHER (aktuelle Zeilenumbrüche):
- Nur Linux:
Funktionen
iundazum Einfügen / Anfügen von Text : Folgen Sie dem Funktionsnamen mit\, gefolgt von einem wörtlichen Zeilenvorschub oder einem gespleißten$'\n'bevor Sie das Textargument angeben .- Nur Linux:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b' - OSX und Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb' - Hinweis:
- Ohne
-eist das Textargument bei der Ausgabe auf macOS (bug?) Unerklärlicherweise nicht newline-terminiert. - Verwenden Sie keine Steuerzeichenzeichen wie
\nund\tim Textargument, da diese nur unter Linux unterstützt werden. - Wenn das Textargument daher tatsächliche innere Zeilenumbrüche enthält,
\-scape diese. - Wenn Sie nach dem Textargument zusätzliche Befehle platzieren möchten, müssen Sie es mit einem (nicht verdeckten) Zeilenvorschub (entweder als Literal oder mit einem Splice) beenden oder mit einer separaten Option
-efortfahren (dies ist eine allgemeine Anforderung, die für alle Versionen gilt). .
- Ohne
- Nur Linux:
Innerhalb Funktionslisten (Anrufe , die in Mehrfachfunktion eingeschlossen
{...}), sollten Sie auch die letzte Funktion zu beenden, vor dem Schließen}, mit;.- Nur Linux:
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS und Linux:
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Nur Linux:
GNU sed -spezifische Merkmale , die in BSD sed vollständig fehlen:
GNU-Funktionen, die Sie vermissen werden, wenn Sie beide Plattformen unterstützen müssen:
Verschiedene Optionen für reguläre Ausdrücke und Substitutionen (sowohl in Mustern für die Zeilenauswahl als auch im ersten Argument der
sFunktion):- Die
IOption für case-INsensitive Regex-Abgleich (unglaublich, BSDsedunterstützt dies überhaupt nicht). - Die
MOption für Mehrzeilenübereinstimmung (wobei^/$dem Anfang / Ende jeder Zeile entspricht ) - Weitere für die
sFunktion spezifische Optionen finden Sie unter https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
- Die
Escape-Sequenzen
Ersatzbedingte Escape-Sequenzen wie
\uim Ersetzungsargument der Funktions///, die die Manipulation der Teilzeichenfolge innerhalb von Grenzen ermöglichen; zBsed 's/^./\u&/' <<<'dog' # -> 'Dog'- siehe http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -BefehlSteuerzeichen-Escape-Sequenzen: zusätzlich zu
\n,\t, ... Codepunkt-basierte Escape-Codes; Beispielsweise stellen alle folgenden\x27\o047(Hex., Oktal, Dezimal) ein einzelnes Anführungszeichen (') dar:\x27,\o047,\d039- siehe https://www.gnu.org/software/sed/manual/ sed.html # Flucht
Adresserweiterungen , z. B.
first~step, um jede step-te Zeileaddr, +N, um N-Zeilen nachaddr, ... - siehe http://www.gnu.org/software/sed/manual/sed. html # Adressen
[1] Die macOS sed Version ist älter als die auf anderen BSD-ähnlichen Systemen wie FreeBSD und PC-BSD. Leider bedeutet dies, dass Sie nicht davon ausgehen können, dass Funktionen, die beispielsweise in FreeBSD funktionieren, auf macOS [gleich] funktionieren.
[2] Die ANSI-C-Anführungszeichenfolge $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' enthält alle ASCII-Steuerzeichen außer \n (und NUL), sodass Sie es in Kombination mit [:print:] für eine ziemlich robuste Emulation von [^\n] :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']
Ersetzen Sie alle Zeilenumbrüche durch Registerkarten
Hinweis: Der Kürze halber verwenden die Befehle hier-Strings ( <<< ) und ANSI-C-Anführungszeichen ( $'...' ) . Beide Shell-Funktionen funktionieren in bash , ksh und zsh .
# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3
# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'
# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'
BSD Sed Hinweise:
Beachten Sie die Notwendigkeit, Bezeichnungen (
:a) und Verzweigungsbefehle (ba) entweder mit tatsächlichen Zeilenumbrüchen oder mit separaten-eOptionen zu beenden.Da Umschaltanweisungen Steuerzeichen wie
\tnicht in der Ersatzzeichenfolge unterstützt werden, ein ANSI - C-Register zitierte Literal wird in die Ersatzzeichenfolge gespleißt.
(Im Regex- Teil erkennt BSD Sed nur\nals Escape-Sequenz).
Text an eine Zeile mit der Funktion 'a' anhängen
Hinweis: Der Kürze halber verwenden die Befehle hier-Strings ( <<< ) und ANSI-C-Anführungszeichen ( $'...' ) . Beide Shell-Funktionen funktionieren in bash , ksh und zsh .
# GNU Sed
$ sed '1 a appended text' <<<'line 1'
line 1
appended text
# BSD Sed (multi-line form)
sed '1 a\
appended text' <<<'line 1'
# BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
sed $'1 a\\\nappended text' <<<'line 1'
Beachten Sie, dass für BSD Seed ein \ gefolgt von einer tatsächlichen Zeilenumbrüche erforderlich ist , um den anzuhängenden Text zu übergeben.
Gleiches gilt für die verwandten Funktionen i (Einfügen) und c (Löschen und Einfügen).