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 --posix att inaktivera (se nedan).
  • Så här använder du bara POSIX-funktioner :

    • (båda versionerna): använd bara alternativen -n och -e (notera, använd inte -E eller -r att aktivera support för utökade reguljära uttryck)

    • GNU sed : lägg till alternativ --posix att 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 : --posix sjä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 \n och \t stöds vanligtvis INTE.
      • Etiketter och grenkommandon (t.ex. b ) måste följas av en faktisk ny linje eller fortsättning via ett separat -e alternativ.
      • Se nedan för mer information.

Båda versionerna implementerar dock tillägg till POSIX-standarden:

  • vilka tillägg de implementerar skiljer sig (GNU sed implementerar 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 -i utan 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.
    • -i aktiverar på ett förnuftigt sätt linjenummering per-input-fil i GNU- sed och 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 -i alla 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.
  • Gemensamma funktioner:

    • Om du begränsar dina sed skript till vad BSD- sed stö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.

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- sed stöder dem (såvida inte --posix används), gör BSD- sed inte 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- sed dokumenterar 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 / -E innebä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 s funktionssamtal), eftersom BSD- sed inte stöder dem i utökade regexer (men underligt nog gör det i grundläggande , där de är POSIX-mandat).
  • Escape-sekvenser med kontrolltecken som \n och \t :

    • I regexer (både i mönster för radval och det första argumentet till s funktionen) antar du att endast \n kä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 med printf (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
    • I ersättningssträngar som används med s kommandot 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'
    • Gör för textargumenten till i och a funktion : använd inte sekvenser för kontrolltecken - se nedan.

  • Etiketter och förgrenings: etiketter såväl som etiketten-namn argumentet till b och t funktioner måste följas av antingen av en bokstavlig newline eller en splitsad-i $'\n' . Alternativt kan du använda flera -e alternativ 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 $\n instanser):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • ELLER (flera -e alternativ):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Funktioner i och a fö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 \n och \t i 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 -e alternativ (detta är ett allmänt krav som gäller alla versioner) .
  • 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'

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:


[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 -e alternativ.

  • Eftersom flyttningssekvenser för kontrolltecken som \t inte 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 \n som 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).



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow