If it's line-based and only one line to replace, I recommend prepending the file itself with the replacement line using printf
, storing that first line in sed
's hold space, and dropping it in as needed. This way you don't have to worry about special characters at all. (The only assumption here is that $VAR
contains a single line of text without any newlines, which is what you said in the comments already.) Other than newlines, VAR could contain anything whatsoever and this would work regardless.
VAR=whatever
{ printf '%s\n' "$VAR";cat somefile; } | sed '1{h;d;};/KEYWORD/g'
printf '%s\n'
will print the contents of $VAR
as a literal string, regardless of its contents, followed by a newline. (echo
will do other things in some cases, for example if the contents of $VAR
begins with a hyphen—it will be interpreted as an option flag being passed to echo
.)
The braces are used to prepend the output of printf
to the contents of somefile
as it's passed to sed
. Whitespace separating the curly braces by themselves is important here, as is the semicolon before the closing curly brace.
1{h;d;};
as a sed
command will store the first line of text in sed
's hold space, then d
elete the line (rather than printing it).
/KEYWORD/
applies the following actions to all lines that contain KEYWORD
. The action is g
et, which gets the contents of the hold space and drops it in place of the pattern space—in other words, the entire current line. (This isn't for replacing only part of a line.) The hold space isn't emptied out, by the way, just copied into the pattern space, replacing whatever is there.
If you want to anchor your regex so it won't match a line which merely contains KEYWORD but only a line where there is nothing else on the line but KEYWORD, add a beginning of line anchor (^
) and end of line anchor ($
) to your regex:
VAR=whatever
{ printf '%s\n' "$VAR";cat somefile; } | sed '1{h;d;};/^KEYWORD$/g'
sed
and have them not be special, just backslash escape them.VAR='hi\/'
gives no such problem.sed(1)
just interprets what it gets. In your case, it gets that via a shell interpolation. I believe you can't do as you want, but check the manual. I know in Perl (which makes a passablesed
replacement, with much richer regular expressions) you can specify a string is to be taken literally, again, check the manual.