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