Sed: insert text after Nth character preceding/following a given string

sed

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.

Best Answer

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;&/"
Related Question