Using sed to edit any one of the occurrence of a matching pattern

A line starting with Fred Flintstone shall be appended with some string.  Look for specified occurrence of Fred Flintstone and append it.

How do I use this command for anyone of the occurrences of such a pattern?  I tried

sed '/Fred Flintstone/ s/$/ someString/2' filename

Apparently the above one isn't working.  It works well for all occurrences, but not a specific occurrence. (Say I want to replace first or second or third [any one of them])

Example File1:

Fred Flintstone 
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

Desired Output File1:

Fred Flintstone 
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

Although you've mentioned sed, these are sort of awk-y tasks:

awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
               if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
  • -v pat="Fred Flintstone" saves the Regex pattern to match as variable pat to be used inside awk expressions

  • $0 ~ pat checks the record against pat for a match; if matched, the count variable is increased by 1 and if count is 2 the record is reset as having the current content plus someString ({count++; if (count == 2) { $0 = $0" someString" ;} ;})

  • 1 is an idiom; as it is truthy, all the records would be printed

Example:

% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

This simple sed command allows you to selectively make the change without using loops (it does use a branch-to-end) or needing GNU extensions or reading the whole file at once:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

Explanation:

  • -r - use extended regex
  • /Fred Flintstone/ - for lines that match this pattern:
    • x - exchange pattern space and hold space (activate the counter)
    • s/$/#/ - add a character to the counter
    • /^#{2}$/ - when the counter is length 2 (substitute any value)
      • x exchange the pattern space and hold space (activate the counted input line)
      • s/.*/& someString/ - append the string to the desired line
      • b - skip to the end of processing for this line so it can be printed
    • x - exchange the pattern space and hold space (activate lines that match the string but not the count)

Indentation levels in the explanation indicate levels of curly brace nesting.

All other lines pass through without processing and are printed.