How to pass a variable containing slashes to sed
BashSedBash Problem Overview
How do you pass a variable containing slashes as a pattern to sed
?
For example, if I have the following variable:
var="/Users/Documents/name/file"
I want to pass it to sed
as so:
sed "s/$var/replace/g" "$file"
However I get errors. How can I circumvent the issue?
Bash Solutions
Solution 1 - Bash
Use an alternate regex delimiter as sed
allows you to use any delimiter (including control characters):
sed "s~$var~replace~g" $file
As mentioned above we can use control character as delimiter as well like:
sed "s^[$var^[replace^[g" file
Where ^[
is typed by pressing Ctrl-V-3 together.
Or else in bash
shell you can use this sed
with \03
as delimiter:
d=$'\03'
sed "s${d}$var${d}replace$d" file
Solution 2 - Bash
A pure bash answer: use parameter expansion to backslash-escape any slashes in the variable:
var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
Solution 3 - Bash
Another way of doing it, although uglier than anubhava's answer, is by escaping all the backslashes in var
using another sed
command:
var=$(echo "$var" | sed 's/\//\\\//g')
then, this will work:
sed "s/$var/replace/g" $file
Solution 4 - Bash
Using /
in sed as a delimiter will conflict with the slashes in the variable when substituted and as a result you will get an error. One way to circumvent this is to use another delimiter that is unique from any characters that is in that variable.
var="/Users/Documents/name/file"
you can use the octothorpe character which suits the occasion (or any other character that is not a /
for ease of use)
sed "s#$var#replace#g"
or
sed 's#$'$var'#replace#g'
this is suitable when the variable does not contain spaces
or
sed 's#$"'$var'"#replace#g'
It is wiser to use the above since we are interested in substituting whatever is in that variable only as compared to double quoting the whole command which can cause your shell to interpet any character that might be considered a special shell character to the shell.
Solution 5 - Bash
Use Perl, where variables are first class citizens, not just expanding macros:
var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
-p
reads the input line by line and prints the line after processing\Q
quotes all the metacharacters in the following string (not needed for the value presented here, but necessary if the value contained[
or some other values special for regular expresisons)
Solution 6 - Bash
This is an old question, but none of the answers here discuss operations other than s/from/to/
in much detail.
The general form of a sed
statement is
*address* *action*
where address can be a regex range or a line number range (or empty, in which case the action is applied to every input line). So for example
sed '1,4d' file
will delete lines 1 through 4 (the address is the line number range 1,4
and the action is the d
delete command); and
sed '/ick/,$s/foo/bar/' file
will replace the first occurrence of foo
with bar
on any line between the first match on the regex ick
and the end of the file (the address is the range /ick/,$
and the action is the s
substitute command s/foo/bar/
).
In this context, if ick
came from a variable, you could do
sed "/$variable/,\$s/foo/bar/"
(notice the use of double quotes instead of single, so that the shell can interpolate the variable, and the necessity to quote the literal dollar sign inside double quotes) but if the variable contains a slash, you will get a syntax error. (The shell expands the variable, then passes the resulting string to sed
; so sed
only sees literal text - it has no concept of the shell's variables.)
The cure is to use a different delimiter (where obviously you need to be able to use a character which cannot occur in the variable's value), but unlike in the s%foo%bar%
case, you also need a backslash before the delimiter if you want to use a different delimiter than the default /
:
sed "\\%$variable%,\$s/foo/bar/" file
(inside single quotes, a single backslash would obviously suffice); or you can separately escape every slash in the value. This particular syntax is Bash only:
sed "/${variable//\//\\/}/,\$s/foo/bar/" file
or if you use a different shell, try
escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file
For clarity, if $variable
contained the string 1/2
then the above commands would be equivalent to
sed '\%1/2%,$s/foo/bar/' file
in the first case, and
sed '/1\/2/,$s/foo/bar/' file
in the second.