0

I am to replace using sed the 3th (or nth to be more general) occurrence in respective line with specified match regex. so far as i can is only to do the first:

$cat file   
# Golden dictionary is a versatile multi purpose reference  
# Copyright (C) 2004-2008 A  
# Copyright (C) 2008-2015 B  
# Copyright (C) 2015-2016 C   

so far as i can is only

$ cat file| sed -E '0,/copy/I s//No-&/'

# Golden dictionary is a versatile multi purpose reference  
# No-Copyright (C) 2004-2008 A  
# Copyright (C) 2008-2015 B  
# Copyright (C) 2015-2016 C 

How to do so by such way for the 3th match only?

  • What is the expected output? – Nasir Riley Jan 27 at 1:15
  • You want the third line that contains the text to be prefixed with No-? Or the third occurrence no matter where it is? – Jeff Schaller Jan 27 at 1:32
  • the third occurrence of respective line, no matter to many occurrences in a line, if 2nd line is # Copyright (C) 2004-2008 Copyright (C) 2009 Copyright (C) 2018 # Copyright (C) 2019 A ,still must find 4th line Copyright (C) 2015-2016 C to be replace then – abdan Jan 27 at 2:15
1

With ed, prefixing the 3rd case-insensitive "copy" with "No-" would be:

ed -s file <<< $'/[Cc][Oo][Pp][Yy]/\n//\n//\ns//No-&/\nw\nq' > /dev/null

The commands are:

  • /[Cc][Oo][Pp][Yy]/ -- search, in a manually case-insensitive way for "copy:
  • // -- repeat the search, twice
  • s//No-&/ -- replace the last match with the "No-" prefix
  • w -- write the change file to disk
  • q -- quit ed

With sed, you could do some pre-work to find the line number to change:

sed -i $(grep -in copy file |awk -F: 'NR==3 { print $1 }')'s/copy/No-&/i' input

Working from left to right,

  • -i -- GNU sed's in-place edit option
  • $( ... ) -- find the line number of the 3rd match of "copy"
    • grep -in copy file -- find the word "copy", case-insensitively in file and report the line numbers of the matches
    • awk -F: 'NR==3 { print $1 }' -- on line 3 of grep's output, split the line on colons and report back column 1 (the line number)
  • s/copy/No-&/i -- replace "copy" with "No-copy", case-insensitively
  • 1
    Or newish gawk could do the change itself: awk -i inplace -vIGNORECASE=1 '/copy/&&++n==3 {sub(/copy/,"No-&")} 1' file (for other awk you could do [Cc] etc and the awk ... file >temp && mv temp file dance) – dave_thompson_085 Jan 27 at 7:41
0

Using awk, counting how many lines contain the string Copyright, and when we reach the third such line, perform a substitution of the first such occurrence on that line:

awk '/Copyright/ && ++n == 3 { sub("Copyright", "No-&") } { print }' file

Using & in the replacement means using whatever the regular expression matched. In this case it will be the string Copyright that will be inserted. This (using &) also works in e.g. sed.

The condition before the first block,

/Copyright/ && ++n == 3

would match the string Copyright against the current line. If it matches, n would be incremented. If the incremented value of n is equal to 3, the block is executed.

Testing:

$ cat file
# Golden dictionary is a versatile multi purpose reference
# Copyright (C) 2004-2008 A
# Copyright (C) 2008-2015 B
# Copyright (C) 2015-2016 C
# Golden dictionary is a versatile multi purpose reference
# Copyright (C) 2004-2008 A
# Copyright (C) 2008-2015 B
# Copyright (C) 2015-2016 C

(the file is the same as yours, but with the contents duplicated once)

$ awk '/Copyright/ && ++n == 3 { sub("Copyright", "No-&") } { print }' file
# Golden dictionary is a versatile multi purpose reference
# Copyright (C) 2004-2008 A
# Copyright (C) 2008-2015 B
# No-Copyright (C) 2015-2016 C
# Golden dictionary is a versatile multi purpose reference
# Copyright (C) 2004-2008 A
# Copyright (C) 2008-2015 B
# Copyright (C) 2015-2016 C

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.