3
$ cat file
cat cat
dog cat
dog puppy
dog cat

Using sed:

$ sed 's/dog/big_dog/' my_file > new_file
$ cat new_file
cat cat 
big_dog cat
big_dog puppy
big_dog cat

My objective is to replace only the second dog with big_dog but that's not happening with:

$ sed 's/dog/big_dog/2' my_file > new_file
cat
dog cat
dog puppy
dog cat

How may I replace only the second occurrence, i.e.:

cat
dog cat
big_dog puppy
dog cat
Nike
  • 1,223
  • 2
  • 19
  • 42
Bishwas Mishra
  • 1,235
  • 1
  • 12
  • 25
  • 2
    always try to put your all requirements in a single post itself. Always try to select any of the provided answers as correct answer to close the thread, cheers. – RavinderSingh13 May 31 '18 at 13:51
  • Updated the question. – Bishwas Mishra May 31 '18 at 17:02
  • 1st thing you haven't covered your samples in code tags(please always do so). 2nd-always try to regard people who have answered by telling them in respective comments either their code worked or not, SO is only for guidance not for a free service. Hope this helps. – RavinderSingh13 May 31 '18 at 17:04
  • What does "covered your samples in code tags" mean? – Bishwas Mishra Jun 01 '18 at 05:39
  • [Sed replace at second occurrence](https://stackoverflow.com/q/46238843/608639), [replace nth occurrence of string in each line of a text file](https://superuser.com/q/143392/173513), [How to replace only the Nth occurrence of a pattern in a file?](https://unix.stackexchange.com/q/181771/56041), [Use sed to use “find and replace” for each second occurrence](https://askubuntu.com/q/914868), etc. – jww Jun 01 '18 at 20:50
  • here's your answer: `sed -i '0,/dog/! {0,/dog/ s/dog/big_dog/}' my_file` – Hashbrown May 19 '20 at 06:21

4 Answers4

6

Like discussed in the comments, this one replaces match on the second row:

$ sed '2s/dog/big_dog/' your_file
dog cat
big_dog puppy
dog cat

To replace the second match with sed, use:

sed ':a;N;$!ba;s/dog/big_dog/2'   your_file_with_foo_on_first_row_to_demonstrate
foo
dog cat
big_dog puppy
dog cat
James Brown
  • 36,089
  • 7
  • 43
  • 59
  • Worked perfectly.Can you point me to the documentation for this? – Bishwas Mishra May 31 '18 at 13:09
  • [Here](https://www.gnu.org/software/sed/manual/sed.txt), search for section _4 Addresses: selecting lines_. – James Brown May 31 '18 at 13:15
  • Oh no. Is there a way to make this not specific to any line? – Bishwas Mishra May 31 '18 at 13:20
  • 1
    @BishwasMishra, try my `awk` code where I have put a variable which could have occurrence number and then it will change to that line as per occurrence, let me know if that helps you? Also please always mention your all requirements in a single time itself in your post. – RavinderSingh13 May 31 '18 at 13:22
  • this does sub on 2nd line, instead of 2nd Occurrence, doesn't it? – Kent May 31 '18 at 13:22
  • @RavinderSingh13 so your cmd is same as `/pup/s/dog/big_&/` ? – Kent May 31 '18 at 13:57
  • 1
    @RavinderSingh13 perhaps I should say sorry.... I posted that comment (just doing the 2nd line sub) regarding this answer. However, you thought I commented on your comment... And after I read your comment, I thought it was the reply by James.... so... you explained again your awk thing under this sed answer.. ^_* – Kent May 31 '18 at 14:25
  • Updated with a solution to replace the second occurrence with sed. – James Brown Jun 01 '18 at 06:28
6

sed for substitute the second occurrence is:

sed "/dog/ {n; :a; /dog/! {N; ba;}; s/dog/big_dog/; :b; n; $! bb}" your_file

Explanation:

/dog/ {           # find the first occurrence that match the pattern (dog)
  n               # print pattern space and read the next line
  :a              # 'a' label to jump to
  /dog/! {        # if pattern space not contains the searched pattern (second occurrence)
    N             # read next line and add it to pattern space
    ba            # jump back to 'a' label, to repeat this conditional check
  }               # after find the second occurrence...
  s/dog/big_dog/  # do the substitution
  :b              # 'b' label to jump to
  n               # print pattern space and read the next line
  $! bb           # while not the last line of the file, repeat from 'b' label
}

Note that last 3 commands are needed to print the rest of the file after found the second occurence, otherwise the substitution may be repeated for each even occurrences of the searched pattern.

Hazzard17
  • 633
  • 7
  • 14
3

Following awk may also help you here.

awk -v line=2 '$1=="dog" && ++count==line{$1="big_dog"} 1'  Input_file

In case of saving output into Input_file itself then append > temp_file && mv temp_file Input_file in above code.

Explanation:

awk -v line=2 '             ##Creating an awk variable line whose value is 2 here.
$1=="dog" && ++count==line{ ##Checking condition if $1 is dog and increasing variable count value is equal to value of line(then do following)
  $1="big_dog"}             ##Assigning $1 to big_dog here.
1                           ##awk works on method of condition then action so by mentioning 1 I am making condition TRUE here so by default action print of line will happen.
'  Input_file               ##Mentioning Input_file here.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
-1

Use below command to replace the word dog with big_dog in 2nd line.

# sed -i '2 s/dog/big_dog/g' my_file
# cat my_file
Output:-
dog cat
big_dog puppy
dog cat

Same If you want to replace from 2nd to 3rd, then you can use below command:-

# sed -i '2,3 s/dog/big_dog/g' my_file