сценарий оболочки: поиск и замена в нескольких строках

#regex #linux #unix #replace

#регулярное выражение #linux #unix #заменить

Вопрос:

Я ищу способ поиска и замены по нескольким строкам с помощью сценария оболочки. Это то, что я пытаюсь сделать:

 source:
[stuff before]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [stuff here, possibly multiple lines.
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]    

target:
[stuff before]
[new content]
[stuff after]
  

Короче говоря, я хочу удалить комментарии и все, что между ними, и заменить каким-нибудь новым контентом. В принципе, я хочу выполнить простую команду sed в нескольких строках и, если возможно, просто использовать некоторые базовые инструменты * nix, без дополнительного языка сценариев.

Ответ №1:

Если вам нужно сопоставить только полные строки, вы можете выполнить эту задачу с awk помощью . Что-то вроде:

     awk -v NEWTEXT=foo 'BEGIN{n=0} /COMMENT_BEGIN/ {n=1} {if (n==0) {print $0}} /COMMENT_END/ {print NEWTEXT; n=0}' < myfile.txt
  

Если файл не так хорошо отформатирован, с комментариями в
той же строке, что и текст, который вы хотите сохранить или удалить, я
бы использовал perl , прочитал весь файл в одну строку,
выполнил сопоставление с регулярным выражением и заменил эту строку, затем записал новую строку в
новый файл. Это не так просто, и вам нужно написать perl скрипт для выполнения этой работы.
Что-то вроде:

 #!/usr/bin/perl
$newtext = "foonbar";
$/ = '';  # no input separator so whole file is read.
$s = <>;  # read whole file from stdin
$startPattern = quotemeta('<!--WIERD_SPECIAL_COMMENT_BEGIN-->');
$endPattern = quotemeta('<!--WIERD_SPECIAL_COMMENT_END-->');
$pattern = $startPattern . '. ' . $endPattern;
$s =~ s/$pattern/$newtext/sg;
print $s;
  

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

1. мой файл довольно прост, так что это должно сработать. из любопытства, есть ли какой-нибудь базовый инструмент unix, который может сделать это за меня, если я не могу использовать строки, или мне нужно что-то более мощное?

2. Я думаю, что это слишком сложно для sed или других базовых инструментов UNIX. Я добавил пример в perl — я думаю, что это самое простое возможное решение, когда оно не работает построчно.

Ответ №2:

sed делает это просто отлично. Следующее настолько просто, насколько это возможно; если вам нужно извлечь данные из строки-разделителя перед начальным разделителем или после конечного разделителя, это будет немного сложнее.

 sed '/<!--WIERD_SPECIAL_COMMENT_BEGIN-->/,/<!--WIERD_SPECIAL_COMMENT_END-->/d' input >output
  

Если у вас есть какой-либо контроль над этим, исправьте написание «странно».

Ответ №3:

другое решение… это можно сделать в однострочном формате, но с использованием регулярных выражений perl, с которыми мне легче работать, чем с sed или awk (которые громоздки при многострочном сопоставлении и замене):

 perl -0 -i -pe 's/<!--WIERD_SPECIAL_COMMENT_BEGIN-->[sS]*<!--WIERD_SPECIAL_COMMENT_END-->/your new content here/gim' yourfile1.txt
  

обратите внимание, что при этом файл будет заменен новым, измененным содержимым.