сопоставить и заменить несколько символов новой строки однострочным SED или PERL

У меня есть входной файл C (myfile.c), который выглядит так:

void func_foo();
void func_bar();

//supercrazytag

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

void func_foo();
void func_bar();
void func_new();

//supercrazytag

До сих пор у меня не получалось использовать SED или PERL. Что не сработало:

sed 's|\n\n//supercrazytag|void func_new();\n\n//supercrazytag|g' < myfile.c
sed 's|(\n\n//supercrazytag)|void func_new();\1|g' < myfile.c

Использование тех же шаблонов с perl -pe "....." тоже не сработало.

Что мне не хватает? Я пробовал много разных подходов, включая this и this и that.


person foob.ar    schedule 29.07.2010    source источник
comment
Вам не следует использовать здесь sed, поскольку он читает строку за строкой, awk - гораздо лучшее решение. Выберите инструмент, который выполняет вашу задачу и делает ее хорошо, для этого sed нет.   -  person Anders    schedule 29.07.2010


Ответы (3)


Для "perl -pe" ваша проблема в том, что он обрабатывается построчно, поэтому он никак не найдет "\ n \ n". Если вы добавите в Perl флаг -0777 (чтобы он обрабатывал весь файл сразу), он заработает:

perl -0777 -pe "s|(\n\n//supercrazytag)|\nvoid func_new();$1|g" myfile.c

Я также изменил (не рекомендуется для этого использования) \ 1 на $ 1 и добавил дополнительный "\ n" в начало замены для удобства чтения.

См. perlrun (Командные переключатели) для объяснения странного вида "-0777 "

person JoelFan    schedule 29.07.2010
comment
Это действительно очень легко читать (за исключением -0777, который, как вы сказали, выглядит немного странно), но sed и друзья не подходят к этому простому синтаксису. - person math; 08.02.2012
comment
Это сработало. Однако он выводил результат на экран, а не изменял фактический файл. Используйте -i как perl -0777 -i -pe "s|(\n\n//supercrazytag)|\nvoid func_new();$1|g" myfile.c, чтобы он действительно изменил файл - person AmmarCSE; 02.02.2017
comment
Другой вариант - перенаправить в другой файл с ›именем файла. - person JoelFan; 03.02.2017

Это будет работать:

sed '/^$/N;s|\n//supercrazytag|void func_new();\n\n//supercrazytag|' myfile.c

ИЗМЕНИТЬ:
Или более кратко:

sed '/^$/N;s|\(\n//supercrazytag\)|void func_new();\n\1|' myfile.c
person Beta    schedule 29.07.2010
comment
Ознакомьтесь с этим ответом, чтобы получить подробное объяснение. о том, что происходит в приведенных выше фрагментах, хотя пример по ссылке не идентичен. - person Matthew; 20.05.2011

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

В псевдокоде:
1. начать чтение и запись строк из файла
2. когда мы находим конец раздела прототипа, вставляем новый текст

use strict;
use warnings;

my $new_prototype = 'void func_new();';
my $seen_proto;

while (<>)
{
    if (/^void \w+\(\);$/ .. /^$/)
    {
        # in the middle of the prototype section
        $seen_proto = 1;
    }
    else
    {
        # this code is run when either before or after the prototype section

        # if we have seen prototypes, we're just after that section - print
        # out the new prototype and then reset our flag so we don't do it twice
        print "$new_prototype\n" and $seen_proto-- if $seen_proto;
    }

    # print out the original line
    print;
}

Поместите этот код в process.pl и запустите через: perl process.pl < mycode.cpp > mycode_new.cpp

person Ether    schedule 29.07.2010