Unterschiede zwischen sed auf Mac OSX und anderen "Standard" sed?

Antworten:

43

Das Verhalten von Shell-Dienstprogrammen unterscheidet sich geringfügig zwischen Unix-Varianten. Es gibt viele Unix- Varianten mit einer komplexen Geschichte . Es gibt Standardisierungsbemühungen wie den POSIX- Standard, der die Single-UNIX-Spezifikation übersteigt . Die meisten Systeme implementieren heutzutage POSIX: 2001, auch bekannt als Single UNIX Specification Version 3 , mit geringfügigen Abweichungen und vielen Erweiterungen. Die Single Unix-Spezifikation ist kein Tutorial, aber Version 3 ist lesbar, wenn Sie bereits eine Vorstellung davon haben, was ein Befehl tut. Sie können nachlesen, ob es sich bei einer Funktion um eine Standardfunktion oder eine Erweiterung eines bestimmten Systems handelt.

Ein Großteil der Unix-Benutzer verwendet Linux und hat keine andere Variante verwendet. Linux wird mit GNU- Dienstprogrammen geliefert, die häufig viele Erweiterungen des Standards enthalten. Sie werden also eine Menge Code finden, der unter Linux funktioniert, aber nicht auf anderen Unices, da er auf diesen Erweiterungen basiert.

Bezüglich sed konsultieren Sie die sed Single Unix-Spezifikation für das Minimum, das jedes System unterstützen soll, die Manpage auf Ihrem System für das, was Ihre Implementierung unterstützt, und das GNU sed-Handbuch für das, was die meisten Leute da draußen verwenden.

Eine der nicht standardmäßigen Erweiterungen in GNU sed unterstützt mehrere Befehle, die zusammen ausgeführt werden. Dieses GNU sed-Programm druckt beispielsweise alle Zeilen, die ein enthalten a, ändert sich jedoch bin czuerst:

sed -ne '/a/ {s/b/c/g; p}'

{und }sind eigentlich separate Befehle. Um eine vollständige Portabilität zu gewährleisten, müssen Sie sie entweder in separaten Zeilen (in einer Datei) oder in separaten -eArgumenten (in der Befehlszeile) angeben . Das Fehlen eines Befehlstrennzeichens nach {und die Verwendung ;als Befehlstrennzeichen sind häufige Erweiterungen. Das Fehlen eines Befehlstrennzeichens }ist eine seltenere Erweiterung. Dies ist standardkonform:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

Dies ist kein Standard, wird aber allgemein akzeptiert:

sed -ne '/a/ { s/b/c/g; p; }'

Eine weitere nicht standardmäßige, aber weit verbreitete Erweiterung ist die Verwendung von \n, um eine neue Zeile in einem sErsetzungstext zu bezeichnen (die Verwendung in einem regulären Ausdruck ist Standard). Die portable Methode besteht darin, Backslash-Newline in das sed-Skript aufzunehmen. Eine weitere gemeinsame Erweiterung ist \+, \?und \|in einer oder mehrere regexps bedeutet, und höchstens einen Wechsel; Portable Basic Regular Expressions haben keine davon. Beispielsweise ist der erste Befehl eine nicht übertragbare Methode, um zusammenhängende Sequenzen von Leerzeichen durch eine neue Zeile zu ersetzen. Der zweite Befehl ist ein standardkonformes Äquivalent.

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'
Gilles 'SO - hör auf böse zu sein'
quelle
Beachten Sie, dass in all diesen Fällen, in denen es um GNU-Erweiterungen geht, die Verwendung nicht dem Standard entspricht. GNU sedselbst ist konform, da es Dinge tut, die der Standard erlaubt (aber nicht erforderlich, nicht spezifiziert). Es gibt Fälle, in denen es nicht konform ist und in denen das Ausführen POSIXLY_CORRECTin der Umgebung hilfreich sein kann. Wie bei s/[\n]//gdiesem muss man den Backlash und die nZeichen entfernen, aber stattdessen die Newlines entfernen. Oder das Verhalten des NBefehls in der letzten Zeile.
Stéphane Chazelas
sed -ne '/a/ { s/b/c/g; p; }'ist Standard seit der Ausgabe 2016 des Standards. Es war immer tragbar. Siehe austingroupbugs.net/view.php?id=944&nbn=7
Stéphane Chazelas
60

OS X wird derzeit mit einer FreeBSD-Version ab 2005 ausgeliefert. Die meisten der folgenden Unterschiede gelten auch für andere BSD-Versionen.

Die sed-Verwendungen von OS X -Efür ERE- und GNU-sed-Verwendungen -r. -Eist ein Alias ​​für -rin GNU sed (hinzugefügt in 4.2, nicht dokumentiert bis 4.3). Neuere Versionen von FreeBSD und NetBSD sed unterstützen sowohl -Eals auch -r. OpenBSD sed unterstützt nur -E.

-i ''funktioniert mit OS X's sed aber nicht mit GNU sed. -ifunktioniert mit GNU sed, neueren Versionen von NetBSD, OpenBSD sed, aber nicht mit OS X sed. -i -efunktioniert mit beiden, aber im Falle von FreeBSD sedwird eine Sicherungskopie der Originaldatei mit dem -eangehängten Dateinamen erstellt (und Sie müssen nicht mehr als einen Ausdruck übergeben sed).

GNU sed interpretiert Escape - Sequenzen wie \t, \n, \001, \x01, \w, und \b. OS X's sed und POSIX sed interpretieren nur \n(aber nicht im Ersatzteil von s).

GNU sed interpretiert \|, \+und \?in BRE aber OS X sed und POSIX sed nicht. \(, \), \{, Und \}sind POSIX BRE.

GNU sed erlaubt das Auslassen von ;Zeilen oder eine neue Zeile }, OS X's sed nicht.

i(insert), a(append) und c(change) müssen in sed und POSIX sed von einem Backslash und einer Newline gefolgt werden, nicht jedoch in GNU sed. GNU sed eine fehlende Newline nach dem von eingefügten Text fügt hinzu i, aoder caber OS X sed ist nicht der Fall. Zum Beispiel sed 1iaist eine GNU-Alternative zu sed $'1i\\\na\n'.

printf a|sed -n pFügt beispielsweise eine neue Zeile in OS Xs sed hinzu, jedoch nicht in GNU sed.

In OS X werden die Modifikatoren I( ohne Berücksichtigung der Groß- und Kleinschreibung) oder M(mit mehreren Zeilen) nicht unterstützt . Neuere Versionen von FreeBSD sed unterstützen I.

Sed von OS X unterstützt -s( --separate), -u( --unbuffered) oder -z( --null-data) nicht.

Eine BSD-Option, die von GNU sed nicht unterstützt wird -a, besteht darin , wan eine Datei anzuhängen, anstatt eine Datei abzuschneiden.

Beispiele für GNU sed-Befehle, die mit sed von OS X nicht funktionieren:

sed /pattern/,+2d # like `sed '/pattern/{N;N;d;}'`
sed -n 0~3p # like `awk NR%3==0`
sed /pattern/Q # like `awk '/pattern/{exit}1'` or `sed -n '/pattern/,$!p'`
sed 's/\b./\u&/g' # \u converts the next character to uppercase
sed 's/^./\l&/' # \l converts the next character to lowercase
sed -i '1ecat file_to_prepend' file # e executes a shell command
sed -n l0 # 0 disables wrapping
Lri
quelle
4
-i -efunktioniert nicht unter OSX. Es wird -eals Suffix eingefügt.
Chris Martin
3
@ChrisMartin ja, in der OS X-Version wird -iimmer ein Suffix benötigt, auch wenn eine leere Zeichenkette. so -i '' -esollte funktionieren.
Waldyrious
@ Waldyrious Es funktioniert nur unter OSX.
Chris Martin
Ja, das ist eine Eigenart dieser Version :)
Waldyrious
3
Der Satz " -i -efunktioniert mit beiden." In Ihrer Antwort heißt es, dass es eine plattformübergreifende Lösung gibt. Anscheinend gibt es das nicht.
Leondepeon
5

Ich habe festgestellt, dass unter Linux und Mac am besten die gleichen Skripte funktionieren:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"
vikrantt
quelle
Oder benutze perlwoher das -ikommt. perl -Tpi -e 's/foo/bar/' -- "$TARGET"
Stéphane Chazelas