Escape a variable for use as content of another script
Bash has a parameter expansion option for exactly this case:
${parameter@Q}
The expansion is a string that is the value of parameter quoted in a format that can be reused as input.
So in this case:
foo_esc="${foo@Q}"
This is supported in Bash 4.4 and up. There are several options for other forms of expansion as well, and for specifically generating complete assignment statements (@A
).
Bash provides a printf
builtin with %q
format specifier, which performs shell escaping for you, even in older (<4.0) versions of Bash:
printf '[%q]\n' "Ne'er do well"
# Prints [Ne\'er\ do\ well]
printf '[%q]\n' 'Sneaky injection $( whoami ) `ls /root`'
# Prints [Sneaky\ injection\ \$\(\ whoami\ \)\ \`ls\ /root\`]
This trick can also be used to return arrays of data from a function:
function getData()
{
printf '%q ' "He'll say hi" 'or `whoami`' 'and then $( byebye )'
}
declare -a DATA="( $( getData ) )"
printf 'DATA: [%q]\n' "${DATA[@]}"
# Prints:
# DATA: [He\'ll\ say\ hi]
# DATA: [or\ \`whoami\`]
# DATA: [and\ then\ \$\(\ byebye\ \)]
Note that the Bash printf
builtin is different than the printf
utility which comes bundled with most Unix-like operating systems. If, for some reason, the printf
command invokes the utility instead of the builtin, you can always execute builtin printf
instead.
I guess I didn't RTFM. It can be done like so:
q_mid=\'\\\'\'
foo_esc="'${foo//\'/$q_mid}'"
Then echo "$foo_esc"
gives the expected 'bar'\''baz'
How I'm actually using it is with a function:
function esc_var {
local mid_q=\'\\\'\'
printf '%s' "'${1//\'/$mid_q}'"
}
...
foo_esc="`esc_var "$foo"`"
Modifying this to use the printf
built-in from Dejay's solution:
function esc_vars {
printf ' %q' "$@" | cut -b 2-
}