Replace " " with "\ " in a file path string with variable expansion

To perform the specific replacement in bash:

path='path/to/directory/foo bar'
echo "${path// /\\ }"
  • Don't use prefix $ when assigning to variables in bash.
  • No spaces are allowed around the =.
  • Note that path is assigned with single quotes, whereas the string replacement occurs in double quotes - this distinction is important: bash does NOT interpret single-quoted strings, whereas you can refer to variables (and do other things) in double-quoted strings; (also, not quoting a variable reference at all has other ramifications, often undesired - in general, double-quote your variable references)

Explanation of string replacement "${path// /\\ }":

  • In order to perform value substitution on a variable, you start with enclosing the variable name in {...}
  • // specifies that ALL occurrences of the following search pattern are to be replaced (use / to replace the first occurrence only).
  • / separates the search pattern, (a single space), from the replacement string, \\ .
  • The replacement string, , must be represented as \\ , because \ has special meaning as an escape char. and must therefore itself be escaped for literal use.

The above is an instance of what bash (somewhat cryptically) calls shell parameter expansion and also parameter expansion and [parameter and] variable expansion. There are many more flavors, such as for extracting a substring, providing a default value, stripping a prefix or suffix, ... - see the BashGuide page on the topic or the manual.

As for what types of expressions are supported in the search and replacement strings:

  • The search expression is a globbing pattern of the same type used in filename expansion (e.g, *.txt); for instance, v='dear me'; echo "${v/m*/you}" yields 'dear you'. Note that the longest match will be used.
    • Additionally, the first character of the pattern has special meaning in this context:
      • /, as we've seen above, causes all matching occurrences of the pattern to be replaced - by default, only the first one is replaced.
      • # causes the rest of the pattern to only match at the beginning of the input variable
      • % only matches at the end
  • The replacement expression is a string that is subject to shell expansions; while there is no support for backreferences, the fact that the string is expanded allows you to have the replacement string reference other variables, contain commands, with $(...), ...; e.g.:
    • v='sweet home'; echo "${v/home/$HOME}" yields, for instance, 'sweet /home/jdoe'.
    • v='It is now %T'; echo "${v/\%T/$(date +%T)}" yields, for instance, It is now 10:05:17.
    • o1=1 o2=3 v="$o1 + $o2 equals result"; echo "${v/result/$(( $o1 + $o2 ))}" yields '1 + 3 equals 4' (I think)

There are many more features and subtleties - refer to the link above.


How about sed? Is that what you're looking for?

#!/bin/bash

path="path/to/directory/foo bar"
new_path=$(echo "$path" | sed 's/ /\\ /g')
echo "New Path: '$new_path"

But as @n0rd pointed out in his comment, is probably better just quoting the path when you want to use it; something like...

path="path/to/directory/foo bar"
echo "test" > "$path"