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--posix
zum Deaktivieren (siehe unten).
- Caveat: GNU
So verwenden Sie nur POSIX-Funktionen :
(beide Versionen): Verwenden Sie nur die Optionen
-n
und-e
(verwenden Sie nicht-E
oder-r
, um die Unterstützung für erweiterte reguläre Ausdrücke zu-E
)GNU
sed
: add Option--posix
POSIX-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:--posix
selbst ist nicht POSIX-konform )Die Verwendung von ausschließlich POSIX-Funktionen bedeutet strengere Formatierungsanforderungen (da auf viele in GNU
sed
verfügbare Funktionen verzichtet wird):- Steuerzeichenfolgen wie
\n
und\t
werden im Allgemeinen NICHT unterstützt. - Beschriftungen und Verzweigungsbefehle (z. B.
b
) müssen über eine separate Option-e
mit 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
sed
implementiert 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
-i
ohne Argument (direkte Aktualisierung ohne Sicherung) ist nicht kompatibel:- BSD
sed
: MUSS-i ''
- GNU
sed
: MUSS nur-i
(Äquivalent:-i''
) verwenden --i ''
funktioniert NICHT.
- BSD
-i
sinnvollerweise die Zeilennummerierung pro Eingabedatei in GNUsed
und den letzten Versionen von BSDsed
(z. B. unter FreeBSD 10), jedoch nicht unter macOS ab 10.12 .
Beachten Sie, dass, wenn keine-i
alle 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
sed
Skripte auf das beschränken, was BSDsed
unterstützt, funktionieren siesed
auch 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: GNUsed
unterstützt sie (sofern nicht--posix
verwendet wird), BSDsed
jedoch 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 (GNUsed
dokumentiert-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
/-E
bedeutet, 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
s
Funktionsaufrufen), da BSDsed
sie 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
\n
und\t
:Nehmen Sie in Regex (sowohl in Mustern für die Zeilenauswahl als auch im ersten Argument für die
s
Funktion) an, dass nur\n
als Escape-Sequenz erkannt wird (selten verwendet, da der Musterraum normalerweise eine einzige Zeile ist (ohne\n
zu beenden). aber nicht innerhalb einer Zeichenklasse , so dass zB[^\n]
nicht funktioniert (wenn Ihre Eingabe keine Steuerzeichen enthält. Außer\t
kö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
i
unda
: Verwenden Sie keine Steuerzeichenfolgen - siehe unten.
Beschriftungen und Verzweigungen : Beschriftungen sowie das Argument mit dem Benennungsnamen für die Funktionen
b
undt
müssen entweder von einem wörtlichen Zeilenumbruch oder einem gespleißten$'\n'
gefolgt werden . Verwenden Sie alternativ mehrere-e
Optionen 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
$\n
Instanzen zusammengefügt):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
- ODER (mehrere
-e
Optionen):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- EITHER (aktuelle Zeilenumbrüche):
- Nur Linux:
Funktionen
i
unda
zum 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
-e
ist das Textargument bei der Ausgabe auf macOS (bug?) Unerklärlicherweise nicht newline-terminiert. - Verwenden Sie keine Steuerzeichenzeichen wie
\n
und\t
im 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
-e
fortfahren (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
s
Funktion):- Die
I
Option für case-INsensitive Regex-Abgleich (unglaublich, BSDsed
unterstützt dies überhaupt nicht). - Die
M
Option für Mehrzeilenübereinstimmung (wobei^
/$
dem Anfang / Ende jeder Zeile entspricht ) - Weitere für die
s
Funktion 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
\u
im 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-e
Optionen zu beenden.Da Umschaltanweisungen Steuerzeichen wie
\t
nicht 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\n
als 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).