Zoeken…


Invoering

Om te citeren uit het verzoek van @ SnoringFrog om een onderwerp te maken:

"Een van de grootste problemen met het gebruik van sed zijn scripts die falen (of op een onverwachte manier slagen) omdat ze voor de een en niet voor de ander zijn geschreven. Een eenvoudige afbouw van de grotere verschillen zou goed zijn."

Opmerkingen

macOS gebruikt de BSD- versie van sed [1] , die in veel opzichten verschilt van de GNU sed versie die wordt geleverd met Linux- distros.

Hun gemene deler is de functionaliteit bepaald door POSIX : zie de POSIX sed spec.

De meest draagbare aanpak is om alleen POSIX-functies te gebruiken , wat echter de functionaliteit beperkt :

  • Met name, POSIX specificeert ondersteunen alleen voor basis reguliere expressies, die veel beperkingen (bijvoorbeeld geen ondersteuning voor | (afwisseling) helemaal niet, geen directe ondersteuning voor + en ? ) En de verschillende ontsnappen eisen.

    • Waarschuwing: GNU sed (zonder -r ), ondersteunt \| , \+ en \? , die NIET POSIX-compatibel is; gebruik --posix om uit te schakelen (zie hieronder).
  • Alleen POSIX-functies gebruiken :

    • (beide versies): gebruik alleen de opties -n en -e (met name, gebruik geen -E of -r om ondersteuning voor uitgebreide reguliere expressies in te schakelen)

    • GNU sed : add optie --posix POSIX-only functionaliteit te verzekeren (je hoeft niet strikt dit nodig, maar zonder dat je zou kunnen komen, per ongeluk met behulp van niet-POSIX voorzien zonder het te merken; caveat: --posix zelf wordt niet POSIX-compliant )

    • Het gebruik van alleen POSIX-functies betekent strengere opmaakvereisten (waardoor veel gemakken beschikbaar zijn in GNU sed ):

      • Controletekensreeksen zoals \n en \t worden over het algemeen NIET ondersteund.
      • Labels en vertakkingscommando's (bijv. b ) moeten worden gevolgd door een daadwerkelijke nieuwe regel of voortzetting via een afzonderlijke optie -e .
      • Zie hieronder voor details.

Beide versies implementeren echter uitbreidingen van de POSIX-standaard:

  • welke extensies ze implementeren verschilt (GNU sed implementeert meer).
  • zelfs die extensies die ze beide implementeren, verschillen gedeeltelijk in syntaxis .

Als u BEIDE platforms moet ondersteunen (bespreking van verschillen):

  • Incompatibele functies:

    • Het gebruik van de optie -i zonder argument (ter plaatse bijwerken zonder back-up) is niet compatibel:

      • BSD sed : MOET -i ''
      • GNU sed : MOET gewoon -i (equivalent: -i'' ) - het gebruik van -i '' werkt NIET.
    • -i schakelt regelnummering per ingangsbestand verstandig in GNU sed en recente versies van BSD sed (bijvoorbeeld op FreeBSD 10) in, maar NIET op macOS vanaf 10.12 .
      Merk op dat bij afwezigheid van -i alle versies cumulatief getallenregels zijn voor alle invoerbestanden.

    • Als de laatste ingangslijn heeft geen opvolgende newline (en afgedrukt):

      • BSD sed : voegt altijd een nieuwe regel toe aan de uitvoer, zelfs als de invoerregel niet eindigt op één.
      • GNU sed : behoudt de status van de volglijn-newline , dwz het voegt alleen een nieuwe regel toe als de invoerregel eindigde in één.
  • Gemeenschappelijke kenmerken:

    • Als u uw sed scripts beperkt tot wat BSD sed ondersteunt, zullen ze over het algemeen ook werken in GNU sed - met de opmerkelijke uitzondering van het gebruik van platformspecifieke uitgebreide regex-functies met -E . Vanzelfsprekend ziet u ook af van extensies die specifiek zijn voor de GNU-versie. Zie volgende sectie.

Richtlijnen voor platformoverschrijdende ondersteuning (OS X / BSD, Linux), aangedreven door de strengere eisen van de BSD-versie :

Merk op dat de shorthands MacOS en Linux nu en dan hieronder zijn gebruikt om te verwijzen naar de BSD en GNU versies van sed , respectievelijk, omdat ze de voorraad versies op elk platform. Het is echter mogelijk om GNU sed op macOS te installeren, bijvoorbeeld met behulp van Homebrew met brew install gnu-sed .

Opmerking : Behalve wanneer de vlaggen -r en -E worden gebruikt ( uitgebreide regexes), komen de onderstaande instructies neer op het schrijven van POSIX-compatibele sed scripts.

  • Voor POSIX compliance, moet je jezelf te beperken tot POSIX Retourenveloppen (basis reguliere expressies) , die, helaas, zoals de naam al doet vermoeden, heel basic.
    Voorbehoud : ga er niet vanuit dat \| , \+ en \? worden ondersteund: hoewel GNU sed ondersteunt (tenzij --posix wordt gebruikt), doet BSD sed dat niet - deze functies zijn niet POSIX-compatibel.
    Terwijl \+ en \? kan worden geëmuleerd op POSIX-conforme wijze:
    \{1,\} voor \+ ,
    \{0,1\} voor \? ,
    \| (afwisseling) kan helaas niet.

  • Voor krachtigere reguliere expressies, gebruik -E (in plaats van -r ) ter ondersteuning van ERE's ( uitgebreide reguliere expressies) (GNU sed documenteert -E , maar het werkt daar wel als alias van -r ; nieuwere versie van BSD sed , zoals op FreeBSD 10, ondersteunt nu ook -r , maar de macOS-versie vanaf 10.12 niet ).
    Voorbehoud : Hoewel het gebruik van -r / -E betekent dat uw opdracht per definitie niet POSIX-compatibel is, moet u zich toch beperken tot POSIX ERE's (uitgebreide reguliere expressies) . Helaas betekent dit dat je niet in staat zult zijn om verschillende bruikbare constructies te gebruiken, met name:

    • woordgebonden beweringen, omdat ze platformspecifiek zijn (bijvoorbeeld \< op Linux, [[:<]] op OS X).
    • back-referenties in reguliere expressies (in tegenstelling tot de "back-referenties" voor het vastleggen van groepswedstrijden in de vervangende string van s functieaanroepen), omdat BSD sed ze niet ondersteunt in uitgebreide regexen (maar, vreemd genoeg, doet dit in basiscodes , waar ze POSIX-verplicht zijn).
  • Escape-reeksen met controletekens zoals \n en \t :

    • Neem in regexen (zowel in patronen voor lijnselectie als het eerste argument voor de functie s ) aan dat alleen \n wordt herkend als een escape-reeks (zelden gebruikt, omdat de patroonruimte meestal een enkele lijn is (zonder terminatie \n ), maar niet binnen een tekenklasse , zodat bijvoorbeeld [^\n] niet werkt; (als uw invoer geen controletekens bevat. Anders dan \t , kunt u [^\n] emuleren met [[:print:][:blank:]] ; anders, splits controle karakters in als letterlijke [2] ) - omvatten in het algemeen controletekens als letterlijke tekens, hetzij via gesplitste ANSI C-geciteerde strings (bijv. $'\t' ) in shells die het ondersteunen ( bash, ksh, zsh ), of via opdrachtvervangingen met printf (bijv. "$(printf '\t')" ) .

      • Alleen Linux:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • OSX en Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • Neem in vervangende tekenreeksen die worden gebruikt met het commando s , aan dat er GEEN escape-escape-reeksen worden ondersteund , dus nogmaals, controletekens. als letterlijk , zoals hierboven.

      • Alleen Linux:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • macOS en Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • Idem voor de tekst argumenten om de i en a functies: gebruik geen controle-tekenreeksen - zie hieronder.

  • Labels en vertakking: labels, alsmede de label-naam argument om de b en t functies moeten worden gevolgd door een letterlijke nieuwe regel of een gesplitst-in $'\n' . U kunt ook meerdere -e opties gebruiken en elk recht na de labelnaam beëindigen.

    • Alleen Linux:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS en Linux:
      • OF (actuele nieuwe regels):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • OF (ingesloten $\n instanties):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • OF (meerdere -e opties):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Functies i en a voor het invoegen / toevoegen van tekst : volg de functienaam door \ , gevolgd door een letterlijke nieuwe regel of een gesplitste $'\n' voordat u het tekstargument opgeeft.

    • Alleen Linux:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • OSX en Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Notitie:
      • Zonder -e wordt het tekstargument op onverklaarbare wijze niet door een nieuwe regel beëindigd bij uitvoer op macOS (bug?).
      • Gebruik geen control-character escapes zoals \n en \t in het tekstargument, omdat ze alleen worden ondersteund op Linux.
      • Als het tekstargument dus echte nieuwe binnenregels heeft, \ -escape ze.
      • Als u extra opdrachten achter het tekstargument wilt plaatsen, moet u deze beëindigen met een (niet-geschaalde) nieuwe regel (letterlijk of gespliced in) of doorgaan met een afzonderlijke optie -e (dit is een algemene vereiste die op alle versies van toepassing is) .
  • Binnen de functie lijsten (meervoudige functie oproepen ingesloten in {...} ), moet u ook de laatste functie te beëindigen, voor de afsluitende } , met ; .

    • Alleen Linux:
      • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS en Linux:
      • sed -n '1 {p;q;}' <<<$'a\nb'

GNU sed specifieke functies ontbreken in BSD sed helemaal:

GNU-functies die je misloopt als je beide platforms moet ondersteunen:


[1] De macOS sed versie is ouder dan de versie op andere BSD-achtige systemen zoals FreeBSD en PC-BSD. Helaas betekent dit dat je niet kunt aannemen dat functies die in FreeBSD werken, bijvoorbeeld [hetzelfde] zullen werken op macOS.

[2] De ANSI C-geciteerde string $'\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' bevat alle ASCII-controletekens behalve \n (en NUL), dus u kunt het gebruiken in combinatie met [:print:] voor een behoorlijk robuuste emulatie van [^\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'']

Vervang alle nieuwe regels door tabbladen

Opmerking: voor de duidelijkheid gebruiken de opdrachten hier-strings ( <<< ) en ANSI C-geciteerde strings ( $'...' ) . Beide shell-functies werken in bash , ksh en 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 merkt op:

  • Let op de noodzaak om labels ( :a ) en vertakkingscommando's ( ba ) te beëindigen met daadwerkelijke nieuwe regels of met afzonderlijke -e opties.

  • Aangezien control tekens escapereeksen zoals \t worden niet ondersteund in de vervangende tekenreeks wordt een ANSI C geciteerde tab letterlijke gesplitst in de vervangingstekenreeks.
    (In het regex- gedeelte herkent BSD Sed alleen \n als een escape-reeks).

Voeg letterlijke tekst toe aan een regel met functie 'a'

Opmerking: voor de duidelijkheid gebruiken de opdrachten hier-strings ( <<< ) en ANSI C-geciteerde strings ( $'...' ) . Beide shell-functies werken in bash , ksh en 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'

Merk op dat BSD Seed een \ vereist, gevolgd door een daadwerkelijke nieuwe regel om de tekst door te voegen.
Hetzelfde geldt voor de bijbehorende functies i (invoegen) en c (verwijderen en invoegen).



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow