How to pass a variable containing slashes to sed

BashSed

Bash 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbuydadipView Question on Stackoverflow
Solution 1 - BashanubhavaView Answer on Stackoverflow
Solution 2 - Bashglenn jackmanView Answer on Stackoverflow
Solution 3 - BashbuydadipView Answer on Stackoverflow
Solution 4 - BashrepzeroView Answer on Stackoverflow
Solution 5 - BashchorobaView Answer on Stackoverflow
Solution 6 - BashtripleeeView Answer on Stackoverflow