Home > database >  How to refresh the line numbers in sed
How to refresh the line numbers in sed

Time:06-16

How can you refresh the line numbers of a sed output inside the same sed command?

I have a sed script as follows -

#!/usr/bin/sed -f 
/pattern/i #inserting a line
1~10i ####

What this does is that it inserts lines wherever the pattern is matched and then inserts #### every ten lines. The problem is that it inserts the hashes every 10 lines according to the line numbers of the original file before inserting the lines for the matching pattern. I want to refresh the line numbers after inserting the lines and use them for inserting the 4 hashes every 10 lines.

Anyway this can be done without piping the output into a new sed?

CodePudding user response:

Using sed

/pattern/i\#inserting a line
/pattern/ { 
    :a
    n
    n
    n
    n
    n
    n
    n
    n
    n
    n
    i\####
    ba
}

CodePudding user response:

Interesting challenge. If your file is not too large, the following may work for you (tested with GNU sed):

#!/usr/bin/sed -nEf
:a; N; $!ba
{
  s/([^\n]*pattern[^\n]*\n)/#inserting a line\n\1/g
  s/\n/ \n/g
  s/\`/####\n/
  :b
  s/(.*####\n([^\n]* \n){9}[^\n]*) \n/\1\n####\n/
  tb
  s/ \n/\n/g
  p
}

Explanations, line by line:

  • No print, extended RE mode (-nE).
  • Loop around label a to concatenate the whole file in the pattern space (reason why its size matters).
  • Add #inserting a line\n before each line containing pattern.
  • Add a space before all endline characters.
  • Insert ####\n before the first line.
  • Label b.
  • Append ####\n' to anything followed by ####\n` and 10 space-terminated lines, removing the final space (to prevent subsequent matches).
  • Goto b if there was a substitution.
  • Remove all spaces at the end of a line.
  • print.

Note: if your file does not contain NUL characters the -z option of GNU sed saves a few commands:

#!/usr/bin/sed -Ezf
s/([^\n]*pattern[^\n]*\n)/#inserting a line\n\1/g
s/\n/ \n/g
s/\`/####\n/
:a
s/(.*####\n([^\n]* \n){9}[^\n]*) \n/\1\n####\n/
ta
s/ \n/\n/g

Note: with the hold space we could probably do the same on the fly, instead of storing the whole file in the pattern space.

CodePudding user response:

You can try this awk:

awk '
    /pattern/ { print "#inserting a line"; offset   }
    (NR-1   offset) % 10 == 0 && NR > 1 { print "####" }
    1
' file
Update

If you're fixated with using sed then you'll have to fork it twice:

sed '/pattern/i\
#inserting a line
' | sed 'n;n;n;n;n;n;n;n;n;a\
####
'
  • Related