Wydaje się na przykład
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
, że musi uciec znaków w celu utworzenia wyrażenia regularnego. W tym przypadku musiałem uciec z nawiasów klamrowych, aby być interpretowanym kilka razy.
Dlaczego? Spodziewałem się, że wszystko będzie postacią regex, chyba że ucieknie. Tj. Wręcz przeciwnie.
11
s/regex//g
już oczekuje wyrażenia regularnego i oczekiwałbym, że to tekst będzie potrzebował do ucieczkiOdpowiedzi:
Wynika to z faktu, że
sed
wykorzystuje POSIX BRE (podstawowe wyrażenia regularne) w przeciwieństwie do ERE (rozszerzone wyrażenia regularne), do których prawdopodobnie przywykłeś od Perla lub znajomych.Ze strony podręcznika
sed(1)
:Odpowiedni cytat z powyższego linku:
Cytując dosłownie komentarz Craiga Sandersa :
źródło
-r
lub--regexp-extended
wiersza poleceń. Jest to przydatne, jeśli chcesz uniknąć dodawania skryptu sed nadmiernemu ucieczce.sed
implementacje (kiedy obsługują ERE, głównie BSD) zwykle używają-E
do tego (co jest o wiele bardziej sensowne, ponieważ jest to ta sama opcja jak dlagrep
. Dlaczego GNUsed
wybrał-r
jest dla mnie tajemnicą).To z powodów historycznych.
Regexp został po raz pierwszy wprowadzony w Uniksie w
ed
użyteczności na początku lat 70. Choćed
była oparta naqed
którego realizacja przez tych samych autorów rozumieć bardziej złożone wyrażenia regularnego,ed
tylko rozumieć^
,$
,[...]
,.
,*
i\
aby uniknąć wszystkich wyżej wymienionych.Teraz, gdy pojawiła się potrzeba posiadania większej liczby operatorów, trzeba było znaleźć sposób na wprowadzenie ich bez naruszania wstecznej kompatybilności. Jeśli skrypt użył
s
ed
polecenias/foo() {/foo (var) {/g
do zastąpienia wszystkich instancji słowem „foo() {
a”foo(var) {
i wprowadzono operator(
lub{
, spowoduje to uszkodzenie tego skryptu.Jednak żaden skrypt nie zrobiłby tego
s/foo\(\) {/foo\(var\) {/
, ponieważ jest to to samo, cos/foo() {/foo(var) {/
nie było powodu do ucieczki,(
ponieważ nie był to operator RE. Tak więc wprowadzenie nowego\(
lub\{
operatora nie psuje kompatybilności wstecznej, ponieważ bardzo mało prawdopodobne jest uszkodzenie istniejącego skryptu przy użyciu starszej składni.Tak właśnie zostało zrobione. Później
\(...\)
dodano początkowo tylko dlas
ed
polecenia, aby robić rzeczy takie jaks/foo\(.\)/\1bar/
i później jakogrep '\(.\)\1'
(ale nie takie rzeczy jak\(xx\)*
).W UnixV7 (1979, a więc prawie dekadę później) dodano nową formę wyrażeń regularnych w nowym narzędziu
egrep
iawk
narzędzia zwane rozszerzonym wyrażeniem regularnym (ponieważ są to nowe narzędzia, nie ma zgodności wstecznej do złamania). Wreszcie zapewnił funkcjonalność dostępną w starożytnej wersji Kena Thompsonaqed
(operator przemiany|
, grupowanie(..)*
) i dodał kilka operatorów takich jak+
i?
(ale nie posiadał funkcji wstecznego wyrażenia podstawowych wyrażeń regularnych).Później dodano BSD
\<
i\>
(zarówno do BRE, jak i ERE), a SysV dodano\{
i\}
tylko do BRE.Dopiero znacznie później
{
i}
zostały dodane do ERE przez takie łamanie wstecznej kompatybilności. Nie wszyscy to dodali. Na przykład GNUawk
do wersji 4.0.0 (2011) nie obsługiwał,{
chyba że został zmuszony do trybu zgodności z POSIX.kiedy GNU
grep
zostało napisane na początku lat 90., dodało wszystkie zalety zarówno BSD, jak i SysV (jak\<
,{
) i zamiast mieć dwie osobne składnie wyrażeń regularnych i silnik dla BRE i ERE, zaimplementowało te same operatory w obu, tylko odpowiedniki BRE z(
,?
,{
,+
muszą być poprzedzone odwrotnym ukośnikiem (być kompatybilny z innymi implementacjami BRE). Dlatego możesz to zrobić.\+
w GNUgrep
(chociaż nie jest to POSIX lub nie jest obsługiwane przez inne implementacje) i możesz to zrobić(.)\1
w GNUegrep
(choć nie jest to POSIX ani obsługiwane przez wiele innych implementacji, w tym GNUawk
).Dodawanie
\x
operatorów nie jest jedynym sposobem na dodanie większej liczby operatorów w sposób kompatybilny wstecz. Na przykładperl
używane(?...)
. Jest to nadal kompatybilne wstecz z ERE, ponieważ(?=...)
nie jest ważne w ERE, to samo dla.*?
.vim
dla podobnych operatorów zrobili to inaczej wprowadzając\@=
lub.\{-}
na przykład.źródło