Это - то, как надежно выполнить не жадное сопоставление многосимвольных строк, используя 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, например, чтобы заменить только второе вхождение:
$ 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