Using sed, how would one insert text after a character that precedes (or follows) some string by N occurrences. As an example, suppose that the line of text to be edited is the following:

command -some -args -c 'a quoted section;some;lines;of code;keyword;more lines;etc();'

After finding this line in a text file (perhaps through the unique string command), I wish to insert text after the second (N=2) semicolon before keyword (i.e., the semicolon separating lines and of). I would specifically like to use sed for the purpose.

Continuing with this example, the expected output would be:

command -some -args -c 'a quoted section;some;lines;INSERTED_STRING;of code;keyword;more lines;etc();'

where INSERTED_STRING; (provided to sed, e.g., via a shell variable) was inserted at the desired position.

  • Can you give examples with real inputs and desired outputs? – Egor Vasilyev Nov 10 '17 at 8:58

I perfer it simple:

sed '/command/s/[^;]*;keyword/INSERTED_STRING;&/'

to insert two fields before the keyword. The general solution would be

sed "/command/s/\([^;]*;\)\{$N\}keyword/INSERTED_STRING;&/"

but note that the N has an offnet of 1 compared to your question: Here, N=2 means to have two fields between the insert and the keyword.

Explanation: /command/ selects only lines with command, so other lines remain untouched. ([^;]*;\) matches one field (a sequence of non-semicolons) including the following semicolon. By following it with \{$N\} the pattern matches $N fields. The following keyword completes this to match keyword and the $N fields before. The replacement pattern consists of the inserted string and &, which gets replaced by everything that was matched (so in the end, it wasn't a replacement, but an insert).

Shorted, and better readable with extended regular expressions:

sed -E "/command/s/([^;]*;){$N}keyword/INSERTED_STRING;&/"

Using sed, you could change only third occurrence of your pattern which is semicolon here.

sed 's/;/;INSERTED_STRING;/3' <<<"$string"

Edit: To replace Nth occurrence of a string before another specific Pattern String keyword ("relative occurrence", in your case 2nd occurrence) if lines matched with uniqe command string.):

sed -r '/command/ s/([^;]*;){1}keyword/INSERTED_STRING;&/' <<<"$string"
  • 2
    1) Surrounding the whole pattern with () and using \1 is not neccessary. You should use & in the replacement instead. 2) Where is N in your answer? What to do for N=42? – Philippos Nov 10 '17 at 10:03
  • @Philippos corrected. that's because OP was asked for second and I was stated 2nd in his case so I didn't add unnecessary {1} there. thanks – αғsнιη Nov 10 '17 at 10:11

If you see the ;-delimited bits as fields of a record, you could do this with awk like so:

$ awk -F';' -vOFS=';' -vstring="NEW TEXT" '{ $4 = $4 ";" string; print }' file
command -some -args -c 'a quoted section;some;lines;of code;NEW TEXT;keyword;more lines;etc();'

awk would, with -F';', break the line in file down into a number of ;-delimited fields. The code would then modify the fourth such field by appending an extra ; and the string held in the variable string (defined on the command line), and output the data with the modified field. The output would likewise be ;-delimited.

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.