Szukaj…


Wprowadzenie

Cytując z prośby @ SnoringFrog o utworzenie tematu:

„Jednym z największych błędów przy użyciu sed są skrypty, które zawodzą (lub nieoczekiwanie kończą się sukcesem), ponieważ zostały napisane dla jednego, a nie drugiego. Dobrze byłoby zlikwidować bardziej poważne różnice.”

Uwagi

macOS używa wersji sed [ sed ] BSD , która pod wieloma względami różni się od wersji sed GNU dostarczanej z dystrybucjami Linuksa .

Ich wspólnym mianownikiem jest funkcjonalność określona przez POSIX : patrz specyfikacja sed POSIX.

Najbardziej przenośnym podejściem jest używanie tylko funkcji POSIX , co jednak ogranicza funkcjonalność :

  • W szczególności POSIX określa wsparcie tylko dla podstawowych wyrażeń regularnych , które mają wiele ograniczeń (np. W ogóle nie obsługują | (alternacji), nie mają bezpośredniego wsparcia dla + i ? ) I różne wymagania dotyczące zmiany znaczenia.

    • Zastrzeżenie: GNU sed (bez -r ), obsługuje \| , \+ i \? , który NIE jest zgodny z POSIX; użyj --posix aby wyłączyć (patrz poniżej).
  • Aby korzystać tylko z funkcji POSIX :

    • (obie wersje): używaj tylko opcji -n i -e (w szczególności nie używaj opcji -E lub -r aby włączyć obsługę rozszerzonych wyrażeń regularnych)

    • GNU sed : opcję Dodaj --posix zapewnienia POSIX tylko funkcjonalność (nie bezwzględnie potrzebne, ale bez niego może skończyć się przypadkowo przy użyciu non-POSIX wyposażony niezauważalnie; zastrzeżenie: --posix sobie nie jest zgodny z POSIX )

    • Korzystanie z funkcji tylko dla POSIX oznacza bardziej rygorystyczne wymagania dotyczące formatowania (rezygnacja z wielu udogodnień dostępnych w GNU sed ):

      • Sekwencje znaków kontrolnych, takie jak \n i \t ogół NIE są obsługiwane.
      • Etykiety i polecenia rozgałęzienia (przykład b ) musi nastąpić w rzeczywistym nowej linii lub przedłużenia poprzez oddzielny -e opcji.
      • Szczegóły poniżej.

Jednak obie wersje implementują rozszerzenia standardu POSIX:

  • jakie rozszerzenia implementują różnią się (GNU sed implementuje więcej).
  • nawet te rozszerzenia, które oba implementują, częściowo różnią się składnią .

Jeśli chcesz wesprzeć OBA platformy (omówienie różnic):

  • Niezgodne funkcje:

    • Użycie opcji -i bez argumentu (aktualizacja w miejscu bez kopii zapasowej) jest niezgodne:

      • BSD sed : MUSI używać -i ''
      • GNU sed : MUSI użyć tylko -i (odpowiednik: -i'' ) - użycie -i '' NIE działa.
    • -i rozsądnie włącza numerację wierszy pliku wejściowego w GNU sed i najnowszych wersjach BSD sed (np. na FreeBSD 10), ale NIE działa na macOS od 10.12 .
      Zauważ, że przy braku -i wszystkie wersje łącznie -i numery wierszy między plikami wejściowymi.

    • Jeśli ostatni wiersz wejściowy nie ma końcowego nowego wiersza (i jest drukowany):

      • BSD sed : zawsze dołącza nowy wiersz na wyjściu, nawet jeśli wiersz wejściowy nie kończy się na jednym.
      • GNU sed : zachowuje stan końcowej nowej linii , tzn. Dodaje nową linię tylko wtedy, gdy linia wejściowa zakończyła się jedną.
  • Wspólne cechy:

    • Jeśli ograniczysz swoje skrypty sed do tego, co obsługuje BSD sed , będą one ogólnie działać również w GNU sed - z godnym uwagi wyjątkiem użycia funkcji rozszerzonego wyrażenia regularnego specyficznych dla platformy z -E . Oczywiście zrezygnujesz także z rozszerzeń specyficznych dla wersji GNU. Zobacz następny rozdział.

Wytyczne dotyczące obsługi między platformami (OS X / BSD, Linux), oparte na surowszych wymaganiach wersji BSD :

Uwaga, że MacOS oraz Linux shorthands są czasami stosowane poniżej odnosi się do wersji BSD i GNU sed , odpowiednio, ponieważ są wersje seryjne na każdej platformie. Możliwe jest jednak zainstalowanie GNU sed na macOS, na przykład za pomocą Homebrew z brew install gnu-sed .

Uwaga : Z wyjątkiem przypadków użycia flag -r i -E ( rozszerzone wyrażenia regularne) poniższe instrukcje sprowadzają się do pisania skryptów sed zgodnych z POSIX .

  • Aby zachować zgodność z POSIX, musisz ograniczyć się do POSIX BRE ( podstawowych wyrażeń regularnych) , które są, niestety, jak sama nazwa wskazuje, dość podstawowe.
    Zastrzeżenie : nie zakładaj, że \| , \+ i \? są obsługiwane: Chociaż GNU sed obsługuje je (chyba że użyto opcji --posix ), BSD sed nie obsługuje - te funkcje nie są zgodne z POSIX.
    Podczas gdy \+ i \? może być emulowany w sposób zgodny z POSIX:
    \{1,\} dla \+ ,
    \{0,1\} dla \? ,
    \| (alternacja) niestety nie może .

  • Aby uzyskać bardziej wydajne wyrażenia regularne, użyj -E (zamiast -r ) do obsługi ERE ( rozszerzone wyrażenia regularne) (GNU sed nie dokumentuje -E , ale działa tam jako alias -r ; nowsza wersja BSD sed , takich jak na FreeBSD 10, teraz również wspierać -r , ale wersja MacOS jak od 10.12 nie robi).
    Zastrzeżenie : Mimo że użycie opcji -r / -E oznacza, że twoje polecenie z definicji nie jest zgodne z POSIX, nadal musisz ograniczyć się do POSIX ERE (rozszerzone wyrażenia regularne) . Niestety oznacza to, że nie będziesz w stanie użyć kilku użytecznych konstrukcji, w szczególności:

    • asercje na granicy słów, ponieważ są one specyficzne dla platformy (np. \< w systemie Linux, [[:<]] w systemie OS X).
    • referencje wsteczne w wyrażeniach regularnych (w przeciwieństwie do „referencji wstecznych” do dopasowywania grup przechwytywania w zastępującym ciągu wywołań funkcji s ), ponieważ BSD sed nie obsługuje ich w rozszerzonych wyrażeniach regularnych (ale, co ciekawe, robi to w podstawowe , jeśli są one upoważnione przez POSIX).
  • Sekwencje specjalne znaków sterujących, takie jak \n i \t :

    • W wyrażeniach regularnych (zarówno we wzorach wyboru linii, jak i pierwszym argumencie funkcji s ) załóżmy, że tylko \n jest rozpoznawana jako sekwencja ucieczki (rzadko używana, ponieważ przestrzeń wzorców jest zwykle pojedynczą linią (bez kończenia \n ), ale nie wewnątrz klasy znaków , tak że np. [^\n] nie działa; (jeśli twoje wejście nie zawiera znaków kontrolnych. innych niż \t , możesz emulować [^\n] pomocą [[:print:][:blank:]] ; w przeciwnym razie splaj znaki kontrolne jako literały [2] ) - ogólnie, dołącz znaki kontrolne jako literały , albo za pomocą splatanych ciągów ANSI C (np. $'\t' ) w powłoki, które go obsługują ( bash, ksh, zsh ) lub przez podstawienia poleceń za pomocą printf (np. "$(printf '\t')" ) .

      • Tylko Linux:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • OSX i Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • W ciągach zastępczych używanych z poleceniem s załóżmy, że nie są obsługiwane sekwencje specjalne znaków kontrolnych, więc ponownie dołącz znaki kontrolne. jak literały , jak wyżej.

      • Tylko Linux:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • macOS i Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • Ditto dla argumentów tekstowych do i i a funkcjami: nie używać sekwencji sterowania znaków - patrz poniżej.

  • Etykiety i rozgałęzienia : po etykietach, a także po argumentie nazwa-etykiety funkcji b i t musi następować albo literałowa nowa linia, albo wstawiona $'\n' . Możesz też użyć wielu opcji -e i zakończyć każdą zaraz po nazwie etykiety.

    • Tylko Linux:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS i Linux:
      • EITHER (rzeczywiste nowe linie):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • LUB (instancje $\n połączone):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • LUB (wiele opcji -e ):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Funkcje i oraz a do wstawiania / dołączania tekstu : przed nazwą funkcji należy wstawić \ , następnie dosłownie nowy wiersz lub wstawić $'\n' przed podaniem argumentu tekstowego.

    • Tylko Linux:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • OSX i Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Uwaga:
      • Bez -e argument tekstowy w niewytłumaczalny sposób nie jest zakończony znakiem nowej linii na wyjściu w systemie macOS (błąd?).
      • Nie używaj znaków kontrolnych, takich jak \n i \t w argumencie tekstowym, ponieważ są one obsługiwane tylko w systemie Linux.
      • Jeśli zatem argument tekstowy ma rzeczywiste wewnętrzne znaki nowej linii, \ -wyświetl je.
      • Jeśli chcesz wstawić dodatkowe polecenia po argumencie tekstowym, musisz zakończyć go znakiem nowej linii (nieokreślonej) (dosłownie lub splicować) lub kontynuować z osobną opcją -e (jest to ogólny wymóg, który dotyczy wszystkich wersji) .
  • Wewnątrz list funkcji (wiele wywołań funkcji zawartych w {...} ) pamiętaj, aby zakończyć ostatnią funkcję przed zamknięciem } pomocą ; .

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

GNU sed - brak specyficznych cech BSD sed :

Funkcje GNU, których przegapisz, jeśli potrzebujesz obsługi obu platform:

  • Różne opcje dopasowania wyrażeń regularnych i podstawiania (zarówno we wzorach wyboru linii, jak i pierwszym argumencie funkcji s ):

  • Sekwencje ewakuacyjne

  • Rozszerzenia adresów , takie jak first~step aby dopasować każdą linię-krok, addr, +N aby dopasować N linii po addr , ... - patrz http://www.gnu.org/software/sed/manual/sed. HTML # Adresy


[1] Wersja macOS sed jest starsza niż wersja na innych systemach podobnych do BSD, takich jak FreeBSD i PC-BSD. Niestety oznacza to, że nie można zakładać, że funkcje działające na przykład we FreeBSD będą działać [tak samo] na macOS.

[2] Ciąg ANSI C cytowany $'\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' zawiera wszystkie znaki sterujące ASCII oprócz \n (i NUL), dzięki czemu można go używać w połączeniu z [:print:] dla dość solidnej emulacji [^\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'']

Zastąp wszystkie znaki nowej linii kartami

Uwaga: Dla zwięzłości polecenia używają ciągów znaków ( <<< ) i ciągów cytowanych w ANSI C ( $'...' ) . Obie te funkcje powłoki działają w bash , ksh i 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'

Notatki BSD Sed:

  • Zwróć uwagę na potrzebę zakończenia etykiet ( :a ) i poleceń rozgałęziających ( ba ) za pomocą rzeczywistych znaków nowej linii lub za pomocą osobnych opcji -e .

  • Ponieważ sekwencje specjalne znaków kontrolnych, takie jak \t nie są obsługiwane w ciągu zastępującym, literał tabulacji cytowany w ANSI C jest łączony w ciąg zastępujący.
    (W części wyrażenia regularnego BSD Sed rozpoznaje tylko \n jako sekwencję zmiany znaczenia).

Dołącz dosłowny tekst do linii z funkcją „a”

Uwaga: Dla zwięzłości polecenia używają ciągów znaków ( <<< ) i ciągów cytowanych w ANSI C ( $'...' ) . Obie te funkcje powłoki działają w bash , ksh i 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'

Zwróć uwagę, że BSD Seed wymaga \ a po nim nowej linii, aby przekazać tekst do dołączenia.
To samo dotyczy powiązanych funkcji i (wstaw) i c (usuń i wstaw).



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow