Oto jak solidnie wykonywać niechciane dopasowanie ciągów wieloznakowych za pomocą sed. Powiedzmy, że chcemy zmienić każdy foo...bar
się <foo...bar>
więc na przykład tego wejścia:
$ cat file
ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV
powinien stać się tym wyjściem:
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV
Aby to zrobić, przekonwertuj foo i pasek na pojedyncze znaki, a następnie użyj negacji tych znaków między nimi:
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/g; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV
W powyższym:
s/@/@A/g; s/{/@B/g; s/}/@C/g
konwertuje {
i }
na łańcuchy znaków zastępczych, które nie mogą istnieć w danych wejściowych, więc te znaki są wtedy dostępne do konwersji foo
i bar
.
s/foo/{/g; s/bar/}/g
współczynnik konwersji foo
i bar
do {
i }
odpowiednio
s/{[^{}]*}/<&>/g
wykonuje op chcemy - konwersja foo...bar
do<foo...bar>
s/}/bar/g; s/{/foo/g
konwertuje {
i }
wraca do foo
ibar
.
s/@C/}/g; s/@B/{/g; s/@A/@/g
konwertuje łańcuchy znaków zastępczych z powrotem na ich oryginalne znaki.
Zauważ, że powyższe nie polega na tym, że żaden konkretny ciąg nie jest obecny na wejściu, ponieważ produkuje takie ciągi w pierwszym kroku, ani nie przejmuje się tym, które wystąpienie określonego wyrażenia regularnego chcesz dopasować, ponieważ możesz użyć {[^{}]*}
tyle razy, ile to konieczne. w wyrażeniu, aby wyodrębnić właściwe dopasowanie i / lub operatorem dopasowania numerycznego seds, np. aby zastąpić tylko 2 wystąpienie:
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/2; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC foo DEF bar GHI <foo KLM bar> NOP foo QRS bar TUV