0

I know that to prepend/append something, I just have to do:

sed -i '/pattern/a new thing!'

However, I'd like to match a line, and prepend something two lines higher.

I'd like to limit tools only to those which come out of the box with ubuntu 12.04, I don't know if awk fits the bill.

Just in case I'm pursuing solution to problem B while I need solution to A: Excerpt of .m3u8 file looks like this:

#EXTINF:4.304300,
output-000.ts
#EXTINF:5.705700,
output-001.ts
#EXTINF:4.304300,
output-002.ts
#EXTINF:5.705700,
output-003.ts

Now, my goal is to insert a line 2 lines before every X'th output-XXX.ts. For example I want to achieve this:

#Inserted line 0
#EXTINF:4.304300,
output-000.ts
#EXTINF:5.705700,
output-001.ts
#Inserted line 1
#EXTINF:4.304300,
output-002.ts
#EXTINF:5.705700,
output-003.ts
  • As I stated, it has to go every Xth occurance of targeted pattern, in this example every second time. My script allows to modify that number, but I kind of assumed that utility tools don't know math to do stuff like that. – Misiur May 5 '15 at 16:10
  • Oh, also the content is ascending integer sequence starting from 0, mirroring which match is it. – Misiur May 5 '15 at 16:16
2

With awk (installed by default on POSIX systems including ubuntu):

POSIXLY_CORRECT=1 awk -v X=2 '
  NR >= 2 && /^output-[0-9]{3}\.ts$/ && ++n % X == 1 {
    print "#Inserted line", i++
  }
  NR>1 {print last}
  {last = $0}
  END{if (NR) print last}' < file.in > file.out

That's for 2 lines above. To generalise to N lines above:

POSIXLY_CORRECT=1 awk -v N=2 -v X=2 '
  BEGIN{N--}
  NR > N {
    if (/^output-[0-9]{3}\.ts$/ && ++n % X == 1)
      print "#Inserted line", i++
    print l[NR % N]
  }
  {l[NR % N] = $0}
  END{
    for (i = NR > N ? NR - N + 1 : 1; i <= NR; i++) print l[i % N]
  }'
  • I think I'll go with your solution. But stupid question, shall I use awk... < myfile..., cat myfile | awk..., or...? I can't seem to get desired output using those. (and awk ... myfile doesn't insert lines as well) – Misiur May 5 '15 at 17:01
  • It seems that n (not N) is empty when I test it using else and printing it. I don't know much about awk, should variable be initialized beforehand? – Misiur May 5 '15 at 17:12
  • Ok, that should be enough spam for today: It seems my awk doesn't support curly braces in regex. I'll google some more. Thank you! – Misiur May 5 '15 at 17:31
  • @Misiur, that'll be an old version of gawk where {} were not enabled unless in POSIX compatibility mode. Best is to use the POSIXLY_CORRECT=1 like in my update to make it work without affecting compatibility with other awk implementations. – Stéphane Chazelas May 5 '15 at 20:01
2

Perl to the rescue:

< .m3u8  perl -ne 'push @w, $_;
                   unshift @w, "#Inserted line " . (0 + $c++) . "\n"
                       if /^output-[0-9]+\.ts/ && 0 == $m++ % 2;
                   print shift @w while @w > 1;
                   }{ print @w;'

@w is the "sliding window" array that keeps the last 2 lines. $m contains the number of matches, i.e. the number of "output-XXXX" lines encountered so far, so if modulo 2 it gives 0, you pick up every 2nd match. unshift inserts a line to the window array at the beginning, shift retrieves it. At the end, you have to output the remaining lines.

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.