Как применить команду sed к согласованному тексту шаблона и заменить в файле?

#bash #awk #sed

#bash #awk #sed

Вопрос:

В моем файле есть текст, и есть другие блоки, соответствующие: build.gradle :

 ... 
staging {
             buildConfigField 'String', 'FLAVOUR_NAME', '"appName"'
             // buildConfigField 'String', 'HOST', '"https://abcd.com"'
             buildConfigField 'String', 'HOST', '"https://example.com"'
             buildConfigField 'String', 'MEDIA_HOST', '"https://example.com"'
             buildConfigField 'String', 'APPHOSTURL', '"https://play.google.com/store/apps/details/"'
             applicationId = "com.example.staging" 
}
 
...
  

Моя цель — найти следующие три строки, включающие строку ‘HOST’ (игнорируя прокомментированные), соответствующую шаблону:

постановка {

Я получил это с помощью:

 sed -n "/staging {/{n;N;N;p;}" build.gradle
  

Вывод:

              buildConfigField 'String', 'FLAVOUR_NAME', '"appName"'
             // buildConfigField 'String', 'HOST', '"https://abcd.com"'
             buildConfigField 'String', 'HOST', '"https://example.com"'
  

Кроме того, мне нужно применить соответствие шаблону из этого вывода и затем заменить текст в файле.

Другая команда, которую я получил, используя, была:

 sed -n "/staging {/{n;N;N;p;}" build.gradle | sed "/^s ///! s/'HOST', .*$/'HOST', '"https://test.com"'/"
  

Вывод:

              buildConfigField 'String', 'FLAVOUR_NAME', '"appName"'
             // buildConfigField 'String', 'HOST', '"https://abcd.com"'
             buildConfigField 'String', 'HOST', '"https://test.com"'
             buildConfigField 'String', 'MEDIA_HOST', '"https://example.com"'
  

Пока все в порядке, но моя проблема в том, что я не знаю, как заменить изменения в существующем файле.

Мне нужен конечный результат (который должен быть заменен в существующем файле) как:

 ... 

staging {
             buildConfigField 'String', 'FLAVOUR_NAME', '"appName"'
             // buildConfigField 'String', 'HOST', '"https://abcd.com"'
             buildConfigField 'String', 'HOST', '"https://test.com"'
             buildConfigField 'String', 'MEDIA_HOST', '"https://example.com"'
             buildConfigField 'String', 'APPHOSTURL', '"https://play.google.com/store/apps/details/"'
             applicationId = "com.example.staging" 
}

...
  

Но sed -i не работает после подачи ввода из вывода канала.

Пожалуйста, укажите мне путь с помощью sed или awk или любого другого.

Комментарии:

1. Добро пожаловать в SO. Особая благодарность за демонстрацию ваших усилий в виде кода. Не могли бы вы, пожалуйста, более четко указать пример ввода и ожидаемого результата в своем вопросе и сообщить нам об этом для лучшего понимания вопроса.

2. Нет ли какого-либо разумного способа, специфичного для Gradle, внести эту модификацию в файл сборки?

3. Я проголосовал за повторное открытие. В этом вопросе уже есть детали, ясность и усилия, с минимальным и воспроизводимым тестовым примером. Задача заключается в том, как изменить файл, объединив две существующие команды sed (предоставленные в вопросе) или любым другим способом awk, sed, bash.

4. Я также голосую за повторное открытие, потому что неясно, какие «детали или ясность» отсутствуют / отсутствуют. Как кто-то может улучшить этот вопрос, не зная, какие «детали или ясность» отсутствуют / отсутствуют?

Ответ №1:

Вот способ объединить две sed команды для этой задачи, не сворачивая ни одной строки.

 sed "/^staging {$/,/^}$/{
        s/(^s*b.*'HOST', '").*("')/1https://test.com2/
    }" file
  

Первый диапазон /^staging {$/,/^}$/ определяет область, в которой {s/...} может произойти следующая замена. Обратите внимание, что если у вас много {} блоков, замена будет проверяться только внутри staging{ } блоков.

Вы можете добавить -i для редактирования на месте после завершения тестирования.

Комментарии:

1. Большое спасибо! Это сработало отлично. Пришлось немного изменить регулярное выражение: sed «/^s staging {$/,/^s } $/{ /^ s //! s/’HOST’, .* $/’HOST’, ‘»test.com «‘/}» build.gradle

Ответ №2:

рассмотрим следующий awk-файл ( changeBuild.awk ):

 # count { and } characters
{ t=$0; brackets =gsub(/{/,"",t)-gsub(/}/,"",t); }
# find where we need a change
$0~where1{ w1=brackets;}
$0~where2{ w2=brackets;}
# change it
$0~changefrom amp;amp; brackets<=w1 amp;amp; $0~where2 { gsub(changefrom, changeto, $0) }
# print it
{ print $0;
  if (brackets<w1){ w1=0 };
  if (brackets<w2){ w2=0 };
}
  

Затем эта строка изменит ваш build.gradle:

 gawk -v where1=staging -v where2='HOST -v changefrom=example.com -v changeto=test.com -f changeBuild.awk build.gradle
  
  • Он подсчитает количество { и } узнает, находитесь ли вы в правильном блоке.
  • where1 и where2 определите, где информация должна быть изменена.
  • changefrom и changeto определите, что нужно изменить.

Поскольку это довольно простой скрипт, ему может потребоваться адаптация, если требуется больше whereX значений, но это должно быть довольно просто добавить.

Подсчет w2 не требуется (здесь), но я использовал более сложный пример с большим количеством уровней ‘{‘ и ‘}’.

TODO:

  • Проверьте наличие закомментированных строк, которые не должны быть изменены.

.

 staging {
             buildConfigField 'String', 'FLAVOUR_NAME', '"appName"'
             // buildConfigField 'String', 'HOST', '"https://abcd.com"'
             buildConfigField 'String', 'HOST', '"https://test.com"'
             buildConfigField 'String', 'MEDIA_HOST', '"https://example.com"'
             buildConfigField 'String', 'APPHOSTURL', '"https://play.google.com/store/apps/details/"'
             applicationId = "com.example.staging"
}
  

РЕДАКТИРОВАТЬ (обнаружена ошибка):

  • $0~changefrom amp;amp; brackets>=w1 amp;amp; $0~where2 было изменено на $0~changefrom amp;amp; brackets<=w1 amp;amp; $0~where2 . Потому что количество скобок больше для подблоков.
  • -v where2=HOST было изменено на -v where2='HOST . Текст «MEDIA_HOST» также соответствовал текстовому хосту. Это добавляет инициал ' к совпадению.

Комментарии:

1. Это сработало, но также изменило ХОСТ в других блоках для случаев, когда совпадение было найдено.

Ответ №3:

Ниже приведен формат файла

versionName 0.0.3

Ожидаемый: versionName 0.0.4

Использовать команду: sed -ie 's/versionName .*/versionName 0.0.4/' "filename"

Ответ №4:

Ниже приведен формат файла

Имя версии 0.0.3

Ожидается: versionName 0.0.4

 sed -ie 's/versionName .*/versionName 0.0.4/' "filename"