Similar to a question posted by me here earlier, am looking for a help in Linux command that performs/does the following that is subtle different from my original question:

Searches for a particular word/phrase case-insensitively in a given file, and then insert/prefix with the character -- (in this case, this is an SQL comment) in the immediate next 'n' lines including the line where the word/phrase was matched in the given file.

EXAMPLE: If I try to search for the phrase "CREATE FUNCTION plpgsql_call_handler" case-insensitively and if it matches at line no.102644, then I expect to insert/prefix the character -- in line no.102644 and the immediate next 2 lines in the given file. In this case, I expect to insert/prefix line nos. 102644,102645,102646 with the character --.

Example file:

102644 CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler
102645     AS '/usr/lib/pgsql/plpgsql.so', 'plpgsql_call_handler'
102646     LANGUAGE c;

I expect/want it to be changed into (in this case, it is an SQL comment):

102644 -- CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler
102645 --    AS '/usr/lib/pgsql/plpgsql.so', 'plpgsql_call_handler'
102646 --    LANGUAGE c;

This is how you'd do it in-place with sed:

sed -r -i -e '/CREATE FUNCTION plpgsql_call_handler/I,+2 s/^/-- /'

(May require GNU sed.)

Replace 2 with the number of lines you want (or use any other sed address forms).

This is much simpler than that perl monstrosity. Also, perl could do it in place by using the -i as well:

perl -i -n -e horrible_perl_code /path/to/file

In both cases if you wish to keep a backup change -i to -i.bak.

  • Yes, it's working as I expected. It's more easy & readable than perl syntax provided by @MadHatter. – Gnanam Apr 12 '11 at 4:41

And yet again, the ol' Swiss Army Chainsaw revs into life:

perl -n -e 'if (/create/i) { s/^(\d+)/\1 --/; print $_; $_=<> ; s/^(\d+)/\1 --/; print $_; $_=<> ; s/^(\d+)/\1 --/; print $_; } else { print $_; }' < /path/to/file

It's not as horrible as it looks! perl -n -e does a loop around each line in the file, not implicitly printing the line, and running the little perl script supplied, on each line.

The little script supplied looks for a string (here it's create, but you can change it as you like) in each line, matching case-insensitively (/i). When it finds the string, it:

  1. replaces all the immediately-sequential digits at the beginning of a line ( ^(\d+) ) with themselves (\1) plus " --",
  2. prints the modified line
  3. reads the next line in ($_=<>)and repeats steps 1 and 2 on that line
  4. reads the next line in and repeats steps 1 and 2 on that line

If the line doesn't contain that string, it prints it unmodified.

I'm sure this could be optimised further, but hopefully that'll do what you want. It sends the modified file to STDOUT; capturing that to a temp file and moving it over the original is left as a (trivial) exercise for the OP!

  • @MadHatter: Could you provide awk/sed equivalent that does the same in place? – Gnanam Apr 11 '11 at 13:14
  • No. awk won't do that, and sed's not my favourite tool. Are you asking for that because this is a homework question, or do you have a genuine business need to do it in place which doing it to a temporary file and moving that into place won't satisfy? – MadHatter Apr 11 '11 at 13:16
  • @MadHatter: Only 2 reasons: 1) I thought awk/sed may have a simplified/ readable format. 2) In fact, I need to do this (modification) exercise in all our different onsite customer servers, so I'm seeing whether this could help me in making this operation in place (in the same input file passed), like the one I've asked before (on deleting). – Gnanam Apr 11 '11 at 13:28
  • With regard to point 2, I fail to understand the functional difference between operating on a file in place and operating on a file to a temporary copy and moving that copy into place, given appropriate checks on the success of each of the steps. You have also been told in the comments to your earlier question (referenced above) that awk won't easily make changes in situ, either. Perhaps someone with more sed experience can provide you with an incantation suitable for that tool, so we can compare complexity with regard to point 1? – MadHatter Apr 11 '11 at 13:33
  • @MadHatter: No issues. I can follow your steps also. But this is just for my understanding, can this not be performed in place using perl? – Gnanam Apr 11 '11 at 13:45

AWK example:

awk 'tolower($0) ~ /create function plpgsql_call_handler/ {n=3;} // { if (n-->0) printf "-- "; print $0;}'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.