4

I have an input C file (myfile.c) that looks like this :

void func_foo();
void func_bar();

//supercrazytag

I want to use a shell command to insert new function prototypes, such that the output becomes:

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

//supercrazytag

So far I've been unsuccessful using SED or PERL. What didn't work:

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

Using the same patterns with perl -pe "....." didn't work either.

What am I missing ? I've tried many different approaches, including this and this and that.

Community
  • 1
  • 1
foob.ar
  • 445
  • 2
  • 9
  • 19
  • 2
    You should not really be using `sed` here since it reads line per line basis, `awk` is a much better solution. Pick a tool that does your task and does it well, for this `sed` does not. – Anders Jul 29 '10 at 17:39

4 Answers4

13

For "perl -pe", your problem is that it is processing line by line, so there is no way it will find "\n\n". If you add the -0777 flag to Perl (to make it process the whole file at once) it will work:

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

I also changed the (deprecated for this usage) \1 to $1 and added an extra "\n" to beginning of the replacement for readability.

See perlrun (Command Switches) for an explanation of the odd-looking "-0777"

JoelFan
  • 37,465
  • 35
  • 132
  • 205
  • 2
    This is really super easy to read (except the -0777, which looks a bit odd as you've said), but sed and friends don't come close to this simple syntax. – math Feb 08 '12 at 13:44
  • 1
    This worked. However, it was printing the result to screen, not changing the actual file. Use `-i` like `perl -0777 -i -pe "s|(\n\n//supercrazytag)|\nvoid func_new();$1|g" myfile.c` to have it actually change the file – AmmarCSE Feb 02 '17 at 08:08
  • 1
    Another option is to redirect to a different file with > filename – JoelFan Feb 03 '17 at 18:29
2

This will work:

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

EDIT:
Or more concisely:

sed '/^$/N;s|\(\n//supercrazytag\)|void func_new();\n\1|' myfile.c
Beta
  • 96,650
  • 16
  • 149
  • 150
  • 2
    Check out [this answer](http://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n/1252191#1252191) for a great explanation of whats going on in the above snippets, though the example at the link isn't identical. – Matthew May 20 '11 at 14:19
0

This is actually an adaptation of an answer I just gave here, on detecting a certain point in a file.

In pseudocode:
1. start reading and writing lines from the file
2. when we find the end of the prototype section, insert some new text

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;
}

Put this code in process.pl and run via: perl process.pl < mycode.cpp > mycode_new.cpp

Community
  • 1
  • 1
Ether
  • 53,118
  • 13
  • 86
  • 159
0
awk  '/supercrazy/{$0="void func_new()\n\n"$0}1'  file
ghostdog74
  • 327,991
  • 56
  • 259
  • 343