sed
BSD / macOS Sed vs. GNU Sed vs. specyfikacja POSIX Sed
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--posixaby wyłączyć (patrz poniżej).
- Zastrzeżenie: GNU
Aby korzystać tylko z funkcji POSIX :
(obie wersje): używaj tylko opcji
-ni-e(w szczególności nie używaj opcji-Elub-raby włączyć obsługę rozszerzonych wyrażeń regularnych)GNU
sed: opcję Dodaj--posixzapewnienia 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:--posixsobie 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
\ni\togół 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-eopcji. - Szczegóły poniżej.
- Sekwencje znaków kontrolnych, takie jak
Jednak obie wersje implementują rozszerzenia standardu POSIX:
- jakie rozszerzenia implementują różnią się (GNU
sedimplementuje 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
-ibez 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.
- BSD
-irozsądnie włącza numerację wierszy pliku wejściowego w GNUsedi najnowszych wersjach BSDsed(np. na FreeBSD 10), ale NIE działa na macOS od 10.12 .
Zauważ, że przy braku-iwszystkie wersje łącznie-inumery 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ą.
- BSD
Wspólne cechy:
- Jeśli ograniczysz swoje skrypty
seddo tego, co obsługuje BSDsed, będą one ogólnie działać również w GNUsed- 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ł.
- Jeśli ograniczysz swoje skrypty
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ż GNUsedobsługuje je (chyba że użyto opcji--posix), BSDsednie 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) (GNUsednie dokumentuje-E, ale działa tam jako alias-r; nowsza wersja BSDsed, 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/-Eoznacza, ż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ż BSDsednie obsługuje ich w rozszerzonych wyrażeniach regularnych (ale, co ciekawe, robi to w podstawowe , jeśli są one upoważnione przez POSIX).
- asercje na granicy słów, ponieważ są one specyficzne dla platformy (np.
Sekwencje specjalne znaków sterujących, takie jak
\ni\t:W wyrażeniach regularnych (zarówno we wzorach wyboru linii, jak i pierwszym argumencie funkcji
s) załóżmy, że tylko\njest 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
- Tylko Linux:
W ciągach zastępczych używanych z poleceniem
szałóż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'
- Tylko Linux:
Ditto dla argumentów tekstowych do
iiafunkcjami: nie używać sekwencji sterowania znaków - patrz poniżej.
Etykiety i rozgałęzienia : po etykietach, a także po argumentie nazwa-etykiety funkcji
bitmusi następować albo literałowa nowa linia, albo wstawiona$'\n'. Możesz też użyć wielu opcji-ei 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
$\npołą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'
- EITHER (rzeczywiste nowe linie):
- Tylko Linux:
Funkcje
iorazado 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
-eargument 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
\ni\tw 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) .
- Bez
- Tylko Linux:
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'
-
- Tylko Linux:
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):- Opcja
Idopasowywania wyrażeń regularnych zależna od wielkości liter (niewiarygodnie, BSDsedogóle tego nie obsługuje). - Opcja
Mdla dopasowania wielu linii (gdzie^/$pasuje do początku / końca każdej linii ) - Aby uzyskać dodatkowe opcje specyficzne dla funkcji
s, patrz https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
- Opcja
Sekwencje ewakuacyjne
Sekwencje specjalne związane z podstawieniem, takie jak
\uw argumencie zastępczym funkcjis///które pozwalają na manipulowanie podciągami w granicach; np.sed 's/^./\u&/' <<<'dog' # -> 'Dog'- patrz http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -KomendaSekwencje specjalne znaków kontrolnych: oprócz
\n,\t, ..., sekwencje specjalne oparte na kodach; na przykład wszystkie następujące sekwencje specjalne (szesnastkowe, ósemkowe, dziesiętne) reprezentują pojedynczy cudzysłów ('):\x27,\o047,\d039- patrz https://www.gnu.org/software/sed/manual/ sed.html # Escapes
Rozszerzenia adresów , takie jak
first~stepaby dopasować każdą linię-krok,addr, +Naby dopasować N linii poaddr, ... - 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
\tnie 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\njako 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).