sed
BSD / macOS Sed vs. GNU Sed vs. POSIX Sed specifikationen
Sök…
Introduktion
För att citera från @ SnoringFrogs begäran om ämnesskapande:
"En av de största gotcherna som använder sed är skript som misslyckas (eller lyckas på ett oväntat sätt) eftersom de var skrivna för det ena och inte det andra. Enkel nedläggning av de större skillnaderna skulle vara bra."
Anmärkningar
macOS använder BSD- versionen av sed [1] , som i många avseenden skiljer sig från GNU- sed versionen som levereras med Linux- distros.
Deras gemensamma nämnare är den funktionalitet som POSIX föreskriver : se POSIX sed specifikationen.
Det mest bärbara tillvägagångssättet är att endast använda POSIX-funktioner , vilket dock begränsar funktionaliteten :
Notera att POSIX specificerar stöd endast för grundläggande reguljära uttryck , som har många begränsningar (t.ex. inget stöd för
|(växling) alls, inget direkt stöd för+och?) Och olika undantagskrav.- Varning: GNU
sed(utan-r), stöder\|,\+och\?, som INTE är POSIX-kompatibel; använd--posixatt inaktivera (se nedan).
- Varning: GNU
Så här använder du bara POSIX-funktioner :
(båda versionerna): använd bara alternativen
-noch-e(notera, använd inte-Eeller-ratt aktivera support för utökade reguljära uttryck)GNU
sed: lägg till alternativ--posixatt säkerställa POSIX-funktionalitet (du behöver inte strikt detta, men utan det kan du avslutas oavsiktligt använda funktioner som inte är POSIX utan att märka; förbehåll :--posixsjälva--posixär inte POSIX-kompatibel )Att använda endast POSIX-funktioner innebär skärpta formateringskrav (går förbi många bekvämligheter tillgängliga i GNU-
sed):- Kontrollkaraktersekvenser som
\noch\tstöds vanligtvis INTE. - Etiketter och grenkommandon (t.ex.
b) måste följas av en faktisk ny linje eller fortsättning via ett separat-ealternativ. - Se nedan för mer information.
- Kontrollkaraktersekvenser som
Båda versionerna implementerar dock tillägg till POSIX-standarden:
- vilka tillägg de implementerar skiljer sig (GNU
sedimplementerar mer). - även de tillägg som de båda implementerar skiljer sig delvis i syntax .
Om du behöver stödja BÅDE plattformar (diskussion om skillnader):
Oförenliga funktioner:
Användning av alternativet
-iutan argument (uppdatering på plats utan säkerhetskopiering) är oförenligt:- BSD
sed: MÅSTE använda-i '' - GNU
sed: MÅSTE använda bara-i(motsvarande:-i'') - att använda-i ''fungerar INTE.
- BSD
-iaktiverar på ett förnuftigt sätt linjenummering per-input-fil i GNU-sedoch senaste versioner av BSD-sed(t.ex. på FreeBSD 10), men gör INTE på macOS från och med 10.12 .
Observera att i avsaknad av-ialla versioner numrerar kumulativt över inputfiler.Om den sista inmatningsraden inte har en efterföljande ny linje (och skrivs ut):
- BSD
sed: lägger alltid till en ny linje på utgången, även om ingångslinjen inte slutar i en. - GNU
sed: bevarar statusen för efterföljande ny linje , dvs. den lägger till en ny linje endast om inmatningsraden slutade på en.
- BSD
Gemensamma funktioner:
- Om du begränsar dina
sedskript till vad BSD-sedstöder fungerar de i allmänhet också i GNU-sed- med det anmärkningsvärda undantaget att använda plattformspecifika utvidgade regex-funktioner med-E. Uppenbarligen kommer du också att avstå från tillägg som är specifika för GNU-versionen. Se nästa avsnitt.
- Om du begränsar dina
Riktlinjer för plattformsstöd (OS X / BSD, Linux), drivna av de strängare kraven i BSD-versionen :
Observera att korthåren macOS och Linux ibland används nedan för att hänvisa till BSD- och GNU-versionerna av sed , eftersom de är aktieversionerna på varje plattform. Det är dock möjligt att installera GNU- sed på macOS, till exempel med hjälp av Homebrew med brew install gnu-sed .
Obs : Förutom när -r och -E flaggorna används ( utvidgade regexer), betyder instruktionerna nedan att skriva POSIX-kompatibla sed skript.
För POSIX-överensstämmelse måste du begränsa dig till POSIX BRE ( grundläggande reguljära uttryck) , som tyvärr, som namnet antyder, är helt grundläggande.
Varning : antar inte att\|,\+och\?stöds: Medan GNU-sedstöder dem (såvida inte--posixanvänds), gör BSD-sedinte det - dessa funktioner är inte POSIX-kompatibla.
Medan\+och\?kan emuleras på POSIX-kompatibelt sätt:
\{1,\}för\+,
\{0,1\}för\?,
\|(växling) kan tyvärr inte.För mer kraftfulla reguljära uttryck, använd
-E(snarare än-r) för att stödja ERE: er ( utvidgade reguljära uttryck) (GNU-seddokumenterar inte-E, men det fungerar där som ett alias av-r; nyare version av BSD-sed, som på FreeBSD 10, stöder nu också-r, men macOS-versionen från och med 10.12 gör det inte ).
Varning : Även om användning av-r/-Einnebär att ditt kommando per definition inte är POSIX-kompatibelt, måste du fortfarande begränsa dig till POSIX ERE (utvidgade regelbundna uttryck) . Tyvärr betyder detta att du inte kommer att kunna använda flera användbara konstruktioner, särskilt:- ordbegränsande påståenden, eftersom de är plattformspecifika (t.ex.
\<på Linux,[[:<]]på OS X). - bakreferenser i reguljära uttryck (i motsats till "bakreferenser" för att fånga gruppmatchningar i ersättningssträngen för
sfunktionssamtal), eftersom BSD-sedinte stöder dem i utökade regexer (men underligt nog gör det i grundläggande , där de är POSIX-mandat).
- ordbegränsande påståenden, eftersom de är plattformspecifika (t.ex.
Escape-sekvenser med kontrolltecken som
\noch\t:I regexer (både i mönster för radval och det första argumentet till
sfunktionen) antar du att endast\nkänns igen som en flygsekvens (sällan används, eftersom mönsterutrymmet vanligtvis är en enda rad (utan att avsluta\n), men inte inuti en karaktärsklass , så att t.ex.[^\n]inte fungerar; (om din ingång inte innehåller några kontrollkar. annat än\t, kan du emulera[^\n]med[[:print:][:blank:]]; annars dela kontrollfält i som bokstäver [2] ) - inkluderar i allmänhet kontrolltecken som bokstäver , antingen via skarvade ANSI C-citerade strängar (t.ex.$'\t') i skal som stöder det (bash,ksh,zsh) eller via kommandosubstitutioner medprintf(t.ex."$(printf '\t')") .- Endast Linux:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b' - OSX och Linux:
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
- Endast Linux:
I ersättningssträngar som används med
skommandot antar du att INGEN kontroll-karaktärsutrymningssekvenser stöds , så, återigen, inkludera kontrollkar. som bokstäver , som ovan.- Endast Linux:
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b' - macOS och Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Endast Linux:
Gör för textargumenten till
iochafunktion : använd inte sekvenser för kontrolltecken - se nedan.
Etiketter och förgrenings: etiketter såväl som etiketten-namn argumentet till
bochtfunktioner måste följas av antingen av en bokstavlig newline eller en splitsad-i$'\n'. Alternativt kan du använda flera-ealternativ och avsluta varje rätt efter etikettnamnet.- Endast Linux:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a' - macOS och Linux:
- ELLER (faktiska nyheter):
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb' - ELLER (splitsade
$\ninstanser):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb' - ELLER (flera
-ealternativ):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- ELLER (faktiska nyheter):
- Endast Linux:
Funktioner
iochaför att infoga / lägga till text : följ funktionsnamnet med\, följt antingen av en bokstavlig nyrad eller en inskriven$'\n'innan du anger textargumentet.- Endast Linux:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b' - OSX och Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb' - Notera:
- Utan
-eär textargumentet oförklarligt inte nylinjeslutet vid utdata på macOS (bug?). - Använd inte kontrollteckenflugter som
\noch\ti textargumentet, eftersom de endast stöds på Linux. - Om textargumentet därför har faktiska inre nyheter,
\-bild av dem. - Om du vill placera ytterligare kommandon efter textargumentet måste du avsluta det med en (oöverskådad) ny linje (vare sig bokstavlig eller skarvad i), eller fortsätta med ett separat
-ealternativ (detta är ett allmänt krav som gäller alla versioner) .
- Utan
- Endast Linux:
Inside funktionslistor (flera funktionsanrop innesluten i
{...}), se till att också avsluta den sista funktionen, före den avslutande}, med;.- Endast Linux:
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS och Linux:
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Endast Linux:
GNU- sed specifika funktioner saknas helt från BSD- sed :
GNU-funktioner du kommer att missa om du behöver stödja båda plattformarna:
Olika regex-matchning och substitutionsalternativ (båda i mönster för radval och det första argumentet till
sfunktionen):- Den
Ialternativet för skiftlägesokänslig regex matchning (otroligt, BSDsedstöder inte detta alls). - Alternativet
Mför matchning med flera linjer (där^/$matchar start / slut på varje rad ) - För ytterligare alternativ som är specifika för
sfunktionen, se https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
- Den
Escape-sekvenser
Substitutionrelaterade flyktningssekvenser som
\ui ersättningsargumentet för funktionens///som möjliggör substringmanipulation , inom gränser; t.ex.sed 's/^./\u&/' <<<'dog' # -> 'Dog'- se http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -KommandoEscape-sekvenser med kontrolltecken: utöver
\n,\t, ..., codepoint-baserade flykt; till exempel representerar alla följande utrymmen (hex., oktal, decimal) en enda citat ('):\x27,\o047,\d039- se https://www.gnu.org/software/sed/manual/ sed.html # Escapes
Adressförlängningar , till exempel
first~stepatt matcha varje steg-rad,addr, +Natt matcha N-rader efteraddr, ... - se http://www.gnu.org/software/sed/manual/sed. html # Adresser
[1] MacOS sed versionen är äldre än versionen på andra BSD-liknande system som FreeBSD och PC-BSD. Tyvärr betyder det att du inte kan anta att funktioner som fungerar i FreeBSD, till exempel, kommer att fungera [samma] på macOS.
[2] Den ANSI C-citerade strängen $'\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' innehåller alla ASCII-kontrolltecken utom \n (och NUL), så du kan använda det i kombination med [:print:] för en ganska robust emulering av [^\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'']
Byt ut alla nya linjer med flikar
Obs: För korthet använder kommandona här-strängar ( <<< ) och ANSI C-citerade strängar ( $'...' ) . Båda dessa skalfunktioner fungerar i bash , ksh och 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 antecknar:
Observera behovet av att avsluta etiketter (
:a) och förgreningskommandon (ba) antingen med faktiska nylinjer eller med separata-ealternativ.Eftersom flyttningssekvenser för kontrolltecken som
\tinte stöds i ersättningssträngen splitsas en ANSI C-citerad flik bokstavlig i ersättningssträngen.
(I regex- delen känner BSD Sed endast igen\nsom en utrymningssekvens).
Lägg till bokstavlig text på en rad med funktionen 'a'
Obs: För korthet använder kommandona här-strängar ( <<< ) och ANSI C-citerade strängar ( $'...' ) . Båda dessa skalfunktioner fungerar i bash , ksh och 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'
Lägg märke till hur BSD Seed kräver en \ följt av en faktisk ny linje för att skicka texten som ska bifogas.
Detsamma gäller för de relaterade funktionerna i (infoga) och c (radera och infoga).