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--posix
aby wyłączyć (patrz poniżej).
- Zastrzeżenie: GNU
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.
- Sekwencje znaków kontrolnych, takie jak
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.
- BSD
-i
rozsądnie włącza numerację wierszy pliku wejściowego w GNUsed
i najnowszych wersjach BSDsed
(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ą.
- BSD
Wspólne cechy:
- Jeśli ograniczysz swoje skrypty
sed
do 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ż GNUsed
obsługuje je (chyba że użyto opcji--posix
), BSDsed
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) (GNUsed
nie 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
/-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ż BSDsed
nie 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
\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
- Tylko Linux:
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'
- Tylko Linux:
Ditto dla argumentów tekstowych do
i
ia
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
it
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'
- EITHER (rzeczywiste nowe linie):
- Tylko Linux:
Funkcje
i
oraza
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) .
- 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
I
dopasowywania wyrażeń regularnych zależna od wielkości liter (niewiarygodnie, BSDsed
ogóle tego nie obsługuje). - Opcja
M
dla 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
\u
w 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~step
aby dopasować każdą linię-krok,addr, +N
aby 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
\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).