sed: заменить слова в шаблоне переменными в одной или нескольких строках - PullRequest
0 голосов
/ 14 июня 2019

Я пишу bash-скрипт, который будет сканировать список файлов PHP, чтобы найти определенную строку «класс X расширяет Y», и заменить Y другой строкой, которую я выбрал (Z).

  • X мне неизвестен, он будет отличаться для каждого файла (мне не нужно знать, что это такое, только что он существует)
  • Y известен и должен совпадать для того, чтобызамена.
  • Z также известен (очевидно)

До сих пор мне удалось придумать строку sed, которая работает, если весь класс X расширяет шаблон Yнаходится на одной строке, но я не могу заставить его работать, например, там, где после X стоит новая строка, а на следующей строке - "extends" (в некоторых случаях с предваряющим символом табуляции / пробела).Я полагаю, возможно, что "класс", X, "extends" и Y будут в 4 отдельных строках и все еще будут действительными PHP?Я не знаю ..

Моя строка sed до сих пор выглядит следующим образом (это внутри цикла):

sed -i -E "s/class (\w+) extends $OLDMODEL/\/\/ Modified by `basename "$0"` - `date` - Original model: $OLDMODEL\n\tclass \1 extends $NEWMODEL/" $FILELOC

В приведенной выше строке $ OLDMODEL - это Y, $ NEWMODEL - это Z,и $ FILELOC - это абсолютный путь к файлу, который нужно изменить.При совпадении команда вставляет комментарий над измененной строкой, в котором записывается имя сценария, дата / время внесения изменения и замещенный класс.

Большинство учебников, которые я видел в Интернете, посвященыпри многострочном сопоставлении с образцом используется sed -e , а не -E , что вызывает проблемы с подстановкой переменных и другими вещами, которые работают только с расширенным регулярным выражением.

X, Y и Z - это буквенные строки с подчеркиванием, например Some_Model_Class_Thing

Буду признателен за любую помощь, которую может мне дать любой.Заранее спасибо:)

Я понимаю, что, возможно, я мог бы использовать Perl или Python, но если это возможно в Sed, я бы хотел, чтобы это работало, особенно если замены в одну строку работают нормально.

Пример ввода:

 1. class FooModule_Sales_Model_Quote extends BarModule_Some_Other_Class
 2. class FooModule_Sales_Model_Quote
            extends BarModule_Some_Other_Class

Пример ввода:

 1. class FooModule_Sales_Model_Quote extends New_Module_Better_Class
 2. class FooModule_Sales_Model_Quote extends New_Module_Better_Class

1 Ответ

2 голосов
/ 14 июня 2019

С GNU sed с опцией -z вы можете:

sed -z 's@class[[:space:]]\+'"$X"'[[:space:]]\+extends[[:space:]]\+'"$Y"'\([[:space:]{]\)@class '"$X"' extends '"$Z"'\1@g'

Протестировано на repl :

cat <<EOF >input
1. class FooModule_Sales_Model_Quote extends BarModule_Some_Other_Class
2. class FooModule_Sales_Model_Quote
            extends BarModule_Some_Other_Class

EOF

X=FooModule_Sales_Model_Quote
Y=BarModule_Some_Other_Class
Z=New_Module_Better_Class

<input sed -z 's@'\
'class[[:space:]]\+'"$X"'[[:space:]]\+extends[[:space:]]\+'"$Y"'\([[:space:]{]\)@'\
'class '"$X"' extends '"$Z"'\1@g'

будет выводить:

1. class FooModule_Sales_Model_Quote extends New_Module_Better_Class
2. class FooModule_Sales_Model_Quote extends New_Module_Better_Class

Обратите внимание, что вы можете сохранить символы новой строки при вводе, просто \([[:space:]]\+\) сохранить их в обратной ссылке и ссылку в замещенной строке.

Я также добавил необходимость \([[:space:]{]\) для пробела или { за extends $Y именем класса.Существует вероятность того, что регулярное выражение будет соответствовать части класса, напр.Вы можете заменить BarModule_Some на что-то и BarModule_Some_Other_Class на что-то другое.Чтобы sed не совпадало с обоими в одном регулярном выражении, вам нужно сопоставить следующий символ после имени класса.

Без gnu sed вы можете заменить символы новой строки на нечитаемый символ tr '\n' $'\01', запустите sedи затем вернуться обратно tr $'\01' '\n'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...