Oto jak solidnie wykonywać niechciane dopasowanie ciągów wieloznakowych za pomocą sed. Powiedzmy, że chcemy zmienić każdy foo...barsię <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/gkonwertuje {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 fooi bar.
s/foo/{/g; s/bar/}/gwspółczynnik konwersji fooi bardo {i }odpowiednio
s/{[^{}]*}/<&>/gwykonuje op chcemy - konwersja foo...bardo<foo...bar>
s/}/bar/g; s/{/foo/gkonwertuje {i }wraca do fooibar .
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