Вот как надежно выполнять несжадное сопоставление многосимвольных строк, используя sed. Допустим, вы хотите изменить каждые foo...bar
на <foo...bar>
, например, такой ввод:
$ cat file
ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV
должно стать таким:
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV
Для этого вы конвертируете foo и bar в отдельные символы, а затем используете отрицание этих символов между ними:
$ 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
В вышеприведенном:
s/@/@A/g; s/{/@B/g; s/}/@C/g
преобразует {
и }
в строки-заполнители, которые не могут существовать во входных данных, поэтому эти символы доступны для преобразования foo
и bar
в.
s/foo/{/g; s/bar/}/g
преобразует foo
и bar
в {
и }
соответственно
s/{[^{}]*}/<&>/g
выполняет операцию, которую мы хотим - преобразование foo...bar
в <foo...bar>
s/}/bar/g; s/{/foo/g
преобразует {
и }
обратно в foo
и bar
.
s/@C/}/g; s/@B/{/g; s/@A/@/g
преобразует строки-заполнители в их исходные символы.
Обратите внимание, что вышеприведенное не зависит от какой-либо конкретной строки, отсутствующей во входных данных, поскольку она производит такие строки на первом шаге, и не заботится о том, какое вхождение какого-либо конкретного регулярного выражения вы хотите сопоставить, так как вы можете использовать {[^{}]*}
столько раз, сколько необходимо в выражении, чтобы выделить фактическое совпадение, которое вы хотите, и / или с оператором числового соответствия seds, например заменить только 2-е вхождение:
$ 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