Заменить многострочную строку в файлах

17

У меня есть несколько файлов, которые я хочу обновить, заменив одну многострочную строку другой многострочной. Что-то вроде:

* Some text, 
* something else
* another thing

И я хочу заменить его на:

* This is completely
* different text

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

Часть проблемы заключается в том, что мне нужно найти список файлов, которые будут обновлены в файловой системе. Я думаю, я могу использовать grep для этого (хотя опять-таки это не так просто сделать с многострочными строками), а затем передать его в sed, может быть?

Есть простой способ сделать это? Sed - вариант, но он неудобен, потому что я должен добавить \ n и т. Д. Есть ли способ сказать «взять входные данные из этого файла, сопоставить их в этих файлах, а затем заменить их содержимым этого другого файла»? Я могу использовать python, если это необходимо, но я хочу что-то быстрое и простое, поэтому, если есть доступная утилита, я бы лучше использовал ее, чем написал свой собственный скрипт (который я знаю, как это сделать).

ventsyv
источник
Возможно, вам следует использовать Perl для этого. stackoverflow.com/questions/1030787/…
orion
3
Итак, вы хотите сопоставить some text, something else another thing, занимает ли он несколько строк? Или вы только хотите соответствовать some text,\nsomething else\nanotherthing?
mikeserv
2
Отредактируйте свой вопрос и уточните, что именно является содержимым каждого файла (ов) и каков желаемый результат.
Джимми
Строка занимает несколько строк. Я предпочитаю игнорировать пробелы при сопоставлении / замене, потому что они не могут быть абсолютно одинаковыми, но это не имеет большого значения, если я просто сделаю 1-1 матч (новые строки и все).
ВЕНЦЫВ

Ответы:

12

Замените "Some ... \ n ... Thing" содержимым файла "new" в одном или нескольких входных файлах.

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
  1. -i изменить input.txt напрямую
  2. -p0 прихлебывать входной файл и распечатывать его в конце
  3. s/regexp/.../s в регулярном выражении .является.|\n
  4. s/.../exp/e заменить на eval(exp)
  5. new - файл, содержащий текст для замены (Это полностью ... другой текст)
  6. если полезно, вы можете расширить исходный текст s/Some text\n...\n...thing\n/...
JJoao
источник
Как я могу сделать то же самое с файлом с именем «before» для поиска (многострочного) содержимого этого файла? Я пытался, но это не работает.
Kvothe
@Kvothe, нам нужно больше деталей ... Предполагая, что «до» не имеет специальных символов, вы можете попробоватьperl -i -p0e ' $b= `cat before`; s/$b/Some thing\n/se' input.txt ...
JJoao
И при условии, что «до» содержит все специальные символы (новые строки, косые черты, скобки), кроме «и».
Kvothe
5
sed -e :n -e '$!N;/\n.*\n/!{$!bn
};  s/some text,\n* *something else\n* *another thing/this is completely\
different text/;P;D' <infile

Боюсь, вам будет трудно найти решение, которое подходит вам, пока вы не разработаете конкретное описание проблемы, но именно для этого лучше всего подходит QA, как я понимаю. Может быть, это даст вам идею - он всегда будет держать 3 строки в шаблонном пространстве за раз - с 2-строчной перспективой - при этом скользя вперед по входному файлу только на строку за раз.

Он должен соответствовать вашей строке независимо от того, занимает ли она несколько строк или нет - до трех, то есть. Но нет никаких положений для отражения этого положения в замене - оно всегда занимает две строки, как написано.

mikeserv
источник
0

Не к сильному (потому что не проверяйте вторую строку, но это легко установить) и может быть не компилятором posix, но очень простым:

sed '/^Some text/{:1;/another thing$/!{N;b 1}
     s/.*/this is completely\ndifferent text/g}' input.txt

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

ПРИМЕЧАНИЕ. Ограничение заключается в том, что за некоторым текстом всегда должна следовать другая вещь .

Костас
источник
Проблема состоит в том, что строка может содержать более 2 строк (до дюжины или около того) и может содержать другие элементы, которые, возможно, должны быть экранированы, такие как вкладки, * и т. Д.
ventsyv
@ventsyv Нет проблем с количеством строк или разделителей - скрипт проверяет только начало и конец. Это вполне достаточно, если стартовая строка может пометить текст для изменения . Если нет, лучше покажите входной пример, чтобы получить правильный шаблон.
Костас