Заменить весь абзац другим из командной строки Linux - PullRequest
4 голосов
/ 31 октября 2011

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

Заменяемый абзац должен совпадать во всей полноте, поскольку существуют подобные текстовые блоки.

например

Заменить

// ----------
// header
// comment
// to be replaced
// ----------

на

// **********
// some replacement
// text
// that could have any
// format
// **********

Я смотрел на использование sed ииз того, что я могу сказать, наибольшее количество строк, над которыми он может работать, - 2 (с командой N).

Мой вопрос: как это сделать из командной строки linux?

РЕДАКТИРОВАТЬ:

Полученное решение: Лучшее решение было Ikegami, полностью командной строки и наилучшим образом подходит для того, что я хотел сделать.

Мое окончательное решение потребовало некоторой настройки;входные данные содержали много специальных символов, как и данные замены.Чтобы справиться с этим, необходимо предварительно обработать данные, чтобы вставить соответствующие символы \ n и escape-символы.Конечным продуктом является сценарий оболочки, который принимает 3 аргумента;Файл, содержащий текст для поиска, Файл, содержащий текст для замены и папку для рекурсивного анализа файлов с расширением .cc и .h.Это довольно легко настроить здесь.

SCRIPT:

#!/bin/bash
if [ -z $1 ]; then
    echo 'First parameter is a path to a file that contains the excerpt to be replaced, this must be supplied'
  exit 1
fi

if [ -z $2 ]; then
    echo 'Second parameter is a path to a file contaiing the text to replace with, this must be supplied'
  exit 1
fi

if [ -z $3 ]; then
    echo 'Third parameter is the path to the folder to recursively parse and replace in'
  exit 1
fi

sed 's!\([]()|\*\$\/&[]\)!\\\1!g' $1 > temp.out
sed ':a;N;$!ba;s/\n/\\n/g' temp.out > final.out
searchString=`cat final.out`
sed 's!\([]|\[]\)!\\\1!g' $2 > replace.out
replaceString=`cat replace.out`

find $3 -regex ".*\.\(cc\|h\)" -execdir perl -i -0777pe "s{$searchString}{$replaceString}" {} +

Ответы [ 4 ]

7 голосов
/ 31 октября 2011
find -name '*.pm' -exec perl -i~ -0777pe'
    s{// ----------\n// header\n// comment\n// to be replaced\n// ----------\n}
     {// **********\n// some replacement\n// text\n// that could have any\n// format\n// **********\n};
' {} +
1 голос
/ 31 октября 2011

Использование perl:

#!/usr/bin/env perl
# script.pl
use strict;
use warnings;
use Inline::Files;

my $lines = join '', <STDIN>; # read stdin
my $repl = join '', <REPL>; # read replacement
my $src = join '', <SRC>; # read source
chomp $repl; # remove trailing \n from $repl
chomp $src; # id. for $src
$lines =~ s@$src@$repl@gm; # global multiline replace 
print $lines; # print output

__SRC__
// ----------
// header
// comment
// to be replaced
// ----------
__REPL__
// **********
// some replacement
// text
// that could have any
// format
// **********

Использование: ./script.pl < yourfile.cpp > output.cpp

Требования: Inline :: Files (установка из cpan)

Проверено на: perl v5.12.4, Linux _ 3.0.0-12-generic # 20-Ubuntu SMP Пт 7 октября 14:56:25 UTC 2011 x86_64 x86_64 x86_64 GNU / Linux

0 голосов
/ 31 октября 2011

Это может сработать:

# cat <<! | sed ':a;N;s/this\nand\nthis\n/something\nelse\n/;ba'
> a
> b
> c
> this
> and
> this
> d
> e
> this
> not
> this
> f
> g
> !
a
b
c 
something
else
d
e
this
not
this 
f
g

Хитрость заключается в том, чтобы отбросить все в пространство шаблона, используя N и цикл :a;...;ba Это, вероятно, более эффективно:

sed '1{h;d};H;$!d;x;s/this\nand\nthis\n/something\nelse\n/g;p;d'

Более универсальное решение может использовать файлы для сопоставления и замены данных следующим образом:

match=$(sed ':a;N;${s/\n/\\n/g};ba;' match_file)
substitute=$(sed ':a;N;${s/\n/\\n/g};ba;' substitute_file)
sed '1{h;d};H;$!d;x;s/'"$match"'/'"$substitute"'/g;p;d' source_file

Другой способ (возможно, менее эффективный), но более чистый:

sed -s '$s/$/\n@@@/' match_file substitute_file | 
sed -r '1{h;d};H;${x;:a;s/^((.*)@@@\n(.*)@@@\n(.*))\2/\1\3/;ta;s/(.*@@@\n){2}//;p};d' - source_file

Последний использует опцию GNU sed --separate для обработки каждого файла как отдельной сущности. Вторая команда sed использует цикл для замены, чтобы устранить жадность .*.

0 голосов
/ 31 октября 2011

Пока комментарии заголовка разграничены уникально (т. Е. Другие комментарии заголовка не начинаются с // ----------), а текст замены постоянен, следующий скрипт awk должен делать то, что вам нужно:

BEGIN { normal = 1 }

/\/\/ ----------/ {
    if (normal) {
        normal = 0;
        print "// **********";
        print "// some replacement";
        print "// text";
        print "// that could have any";
        print "// format";
        print "// **********";
    } else {
        normal = 1;
        next;
    }
}

{
    if (normal) print;
}

Это печатает все, что видит, пока не попадет в разделитель абзаца.Когда он видит первый, он печатает абзац замены.Пока он не увидит разделитель 2-го абзаца, он ничего не напечатает.Когда он видит разделитель 2-го абзаца, он снова начинает нормально печатать строки со следующей строки.

Хотя технически вы можете сделать это из командной строки, вы можете столкнуться с хитрыми проблемами с цитированием оболочки, особенно если заменаТекст имеет одинарные кавычки.Может быть проще поместить скрипт в файл.Просто поместите #!/usr/bin/awk -f (или любой другой путь which awk) вверху.

РЕДАКТИРОВАТЬ

Чтобы сопоставить несколько строк в awk, вам нужно использоватьgetline.Возможно, что-то вроде этого:

/\/\/ ----------/ {
    lines[0] = "// header";
    lines[1] = "// comment";
    lines[2] = "// to be replaced";
    lines[3] = "// ----------";

    linesRead = $0 "\n";
    for (i = 0; i < 4; i++) {
         getline line;
         linesRead = linesRead line;
         if (line != lines[i]) {
             print linesRead; # print partial matches
             next;
         }
    }

    # print the replacement paragraph here
    next;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...