haykart
haykart

Reputation: 957

Replacing strings in files with bash sed or a scripting language (TCL, perl)

I have a list of C++ source files, which have the following structure:

// A lot of stuff
#include <current/parser/support/base.hpp>
// ...
#include <current/parser/iterators/begin.hpp>
// ...

I need to replace lines like

#include <current/parser/support/base.hpp>

with

#include <support_base.hpp>

Namely, omit the current/parser and replace the separator (/) with _. Is this possible to do with bash sed or a scripting language?

EDIT: Sorry, forgot to mention that I want to replace anything like

#include <current/parser/*/*/*/*>

Anything can go after current/parser, and with any depth.

Upvotes: 2

Views: 401

Answers (4)

Miller
Miller

Reputation: 35198

Using a perl one-liner

perl -i -pe 's{^#include <\Kcurrent/parser/([^>]*)}{$1 =~ y|/|_|r}e;' file.cpp

Or without regex features greater than perl 5.10

perl -i -pe 's{(?<=^#include <)current/parser/([^>]*)}{join "_", split "/", $1}e;' file.cpp

Explanation:

Switches:

  • -i: Edit files in place (makes backup if extension supplied)
  • -p: Creates a while(<>){...; print} loop for each line in your input file.
  • -e: Tells perl to execute the code on command line.

Upvotes: 0

konsolebox
konsolebox

Reputation: 75498

Using sed:

sed -i -e '/#include <current\/parser\/support\/base\.hpp>/{ s|current/parser/||; s|/|_|; }' -- file1 file2 file3

Edit:

sed -i -e '/#include <current\/parser\/.*>/{ s|current/parser/||; s|/|_|g; }' -- file1 file2 file3

Would remove currrent/parsers/ and replace all / with _. Example result file:

// A lot of stuff
#include <support_base.hpp>
// ...
#include <iterators_begin.hpp>
// ...

Some details:

/#include <current\/parser\/.*>/  --  Matcher.
s|current/parser/||               --  Deletes `current/parser/` in matched line.
s|/|_|g                           --  Replaces all `/` with `_` in same line.

Upvotes: 3

user1558455
user1558455

Reputation:

You can try it with sed and -r for regular expression:

sed -r 's|#include <current/parser/support/base\.hpp>|#include <support_base.hpp>|g' file

But using this way could kill your code. So be carefull :)

Upvotes: 0

Jerry
Jerry

Reputation: 71548

Going with Tcl:

# Open the file for reading
set fin [open filein.c r]
# Open the file to write the output
set fout [open fileout.c w]

# Loop through each line
while {[gets $fin line] != -1} {
    # Check for lines beginning with "^#include <current/parser/"
    #
    # ^ matches the beginning of the line
    # ([^>]*) matches the part after "#include <current/parser/" and stores it
    #    in the variable 'match'

    if {[regexp {^#include <current/parser/([^>]*)>} $line - match]} {
        # the edited line is now built using the match from above after replacing
        #    forward slashes with underscores
        set newline "#include <[string map {/ _} $match]>"
    } else {
        set newline $line
    }
    # Put output to the file
    puts $fout $newline
}

# Close all channels
close $fin
close $fout

Output with the provided input:

// A lot of stuff
#include <support_base.hpp>
// ...
#include <iterators_begin.hpp>
// ...

Demo on codepad (I edited the code a bit since I can't have a channel open to read/write in files there)

Upvotes: 3

Related Questions