Используя sed, как можно дополнительно преобразовать групповые обратные ссылки?
Могу ли я использовать sed для замены соответствия регулярному выражению преобразованием групповой обратной ссылки в регулярном выражении?
Задача
Предположим, я хочу заменить строки вида:
(@ -p <fqdn>)
Таких совпадений может быть несколько на строку.
С:
<fqdn with dots replaced by underscores>
Пример
com.xyz (@ -p com.abc.def) com.pqr.stu (@ -p com.ghi)
Станет:
com.xyz com_abc_def com.pqr.stu com_ghi
Идеи
Чтобы начать работу над решением, рассмотрим:
$ sed 's|(@ -p ([^)]*))|1|' <<<"com.xyz (@ -p com.abc) com.pqr (@ -p com.ghi)"
com.xyz com.abc com.pqr com.ghi
Это делает соответствующий выбор; однако теперь мне все еще нужно, чтобы часть 1
была преобразована с помощью s|.|_|g
.
Примечания:
- я добавляю это к существующему сценарию sed, поэтому я очень предпочитаю решение sed, а не передачу результата моего текущего сценария sed другому строковому процессору, такому как awk. Если нет решения sed для этого проблема, то я рассмотрю awk решения в следующем.
- мой вопрос специфичен для шаблона, показанного в приведенном выше примере.
3 ответа:
Вы можете использовать
gnu awk
:s='com.xyz (@ -p com.abc.def) com.pqr.stu' awk -v RS='\\(@ -p [^)]+\\)' '{ ORS=gensub(/.* |\)/,"","g",gensub(/\./,"_","g",RT))} 1' <<< "$s" com.xyz com_abc_def com.pqr.stu
Если целевая строка встречается только один раз (на строку ввода), вы можете использовать пространство удержания для выполнения двойной замены, например:
Единственная замена
#Copy input line to the hold space: A(@B)C -- A(@B)C h #Replace the target substring with (@) (a "marker" string): A(@)C -- A(@B)C s/(@ -p [^)]*)/(@)/ #Exchange the content of the pattern space and hold space: A(@B) -- A(@)C x #Strip off anything except the target substring value: B -- A(@)C s/.*(@ -p \([^)]*\)).*/\1/ #Modify the target substring as appropriate: B' -- A(@)C y/./_/ #Append the content of the hold space back to the pattern space: B'\nA(@)C -- G #Merge the lines, replacing the "marker" string with the processed value: AB'C s/\(.*\)\n\(.*\)(@)/\2\1/
Пример вывода:
%echo "com.xyz (@ -p com.abc) com.pqr" | sed -f doublereplace.sed com.xyz com_abc com.pqr
Множественные замены
Зацикленная версия будет выглядеть следующим образом:
#Loop label :start /(@/ { #Copy input line to the hold space: A(@B)C -- A(@B)C h #Replace the target substring with (@) (a "marker" string): A(@)C -- A(@B)C s/(@ -p [^)]*)/(@)/ #Exchange the content of the pattern space and hold space: A(@B) -- A(@)C x #Strip off anything except the target substring value: B -- A(@)C s/[^(]*(@ -p \([^)]*\)).*/\1/ #Modify the target substring as appropriate: B' -- A(@)C y/./_/ #Append the content of the hold space back to the pattern space: B'\nA(@)C -- G #Merge the lines, replacing marker string with the processed value: AB'C s/\(.*\)\n\(.*\)(@)/\2\1/ #Loop b start }
Пример вывода:
%echo "com.xyz (@ -p com.abc.def) com.pqr.stu (@ -p com.ghi)" | sed -f doublereplace.sed com.xyz com_abc_def com.pqr.stu com_ghi
Закаленный
Немного более надежная версия может использовать новые строки в качестве разделителей / маркерной строки:
#Loop label :start /(@ -p [^)]*)/ { #Copy input line to the hold space: A(@B)C -- A(@B)C h #Replace the target substring with (@) (a "marker" string): A\nC -- A(@B)C s/(@ -p [^)]*)/\n/ #Exchange the content of the pattern space and hold space: A(@B)C -- A\nC x #Isolate the first instance of a target substring to a separate line A\n(@B)\nC -- A\n\C s/\((@ -p [^)]*)\)/\n\1\n/1 #Strip off anything except the target substring value: B -- A\nC s/.*\n(@ -p \([^)]*\))\n.*/\1/ #Modify the target substring as appropriate: B' -- A\nC y/./_/ #Append the content of the hold space back to the pattern space: B'\nA\nC -- G #Merge the lines, replacing marker string with the processed value: AB'C s/\(.*\)\n\(.*\)\n/\2\1/ #Loop b start }
Это позволит для любого неполного
@()
конструкции во входных данных, как(@ t.i.m.e.s)
:%echo "com.xyz (@ -p com.abc.def) fails (@ t.i.m.e.s) com.pqr.stu (@ -p com.ghi)" | sed -f doublereplace.sed com.xyz com_abc_def fails (@ t.i.m.e.s) com.pqr.stu com_ghi