Reputation: 1617
I'm having difficulty nested quotes within a bash script
argv="su -c '$RVM_PATH wrapper $config_rvm \'$PASSENGER_RVM_BIN $command $options\'' web"
eval $argv
The above got me
eval: line 162: unexpected EOF while looking for matching `''
eval: line 163: syntax error: unexpected end of file
Upvotes: 12
Views: 17078
Reputation: 46983
eval
with correctly quoted argumentsThe following function uses the shell's own quoting mechanism to that I don't have to worry about how to correctly quote things:
function token_quote {
local quoted=()
for token; do
quoted+=( "$(printf '%q' "$token")" )
done
printf '%s\n' "${quoted[*]}"
}
Example usage:
$ token_quote token 'single token' token
token single\ token token
Above, note the single token
's space is quoted as \
.
$ set $(token_quote token 'single token' token)
$ eval printf '%s\\n' "$@"
token
single token
token
$
This shows that the tokens are indeed kept separate.
Given some untrusted user input:
% input="Trying to hack you; date"
Construct a command to eval:
% cmd=(echo "User gave:" "$input")
Eval it, with seemingly correct quoting:
% eval "$(echo "${cmd[@]}")"
User gave: Trying to hack you
Thu Sep 27 20:41:31 +07 2018
Note you were hacked. date
was executed rather than being printed literally.
Instead with token_quote()
:
% eval "$(token_quote "${cmd[@]}")"
User gave: Trying to hack you; date
%
eval
isn't evil - it's just misunderstood :)
Upvotes: 0
Reputation: 1617
argv="su -c \"$RVM_PATH wrapper $config_rvm \\\"$PASSENGER_RVM_BIN $command $options\\\"\" web"
Upvotes: 13
Reputation: 183484
That's because \'
doesn't have any special meaning within a single-quoted string; it means simply "backslash, followed by end-of-string".
One option is to use $'...'
instead of '...
'; that will let you use backslash-escapes. It would look like this:
argv="su -c $'$RVM_PATH wrapper $config_rvm \'$PASSENGER_RVM_BIN $command $options\'' web"
The downside is that if there's any chance that $RVM_PATH
, $config_rvm
, or any of the other variables could include a backslash, then it too could be interpreted as introducing a backslash-escape.
Upvotes: 9