Variable containing multiple args with quotes in Bash Variable containing multiple args with quotes in Bash bash bash

Variable containing multiple args with quotes in Bash


You might consider using an array for the args, something like this:

args=( "$f1" "$f2" )ls "${args[@]}"

(The problem you're hitting at the moment is that once interpolation has happened there's no difference between intra- and inter- filename spaces.)


eval will first evaluate any expansions and quoting and then execute the resultant string as if it had been typed into the shell.

f1="file n1"f2="file n2"args="'${f1//\'/}' '${f2//\'/}'"# will execute `ls 'file n1' 'file n2'`eval "ls $args"

The above example uses input sanitisation to prevent arbitrary commands being executed (f1="'; rm -rf '/").

When using eval it is important to consider the source of the data being eval'd. If eval is being used for command compositing (building a command dynamically), with all values static, and defined by your script, there are likely no additional considerations. If your script is a persistent process, running as root, reading values from a world writable pipe, it's probably a good idea to ensure user input is always treated as literal data.

The input sanitisation above relies on the fact that single quoted strings are treated as literals, that is, they are not expanded, and escape sequences are not processed. To prevent arbitrary command execution we need to prevent the single quoted string being terminated, this can be done by removing any single quotes from the input.

If you're sure you don't need command sanitisation then the string substitutions can be omitted:

f1="file n1"f2="file n2"args="'${f1}' '${f2}'"# will execute `ls 'file n1' 'file n2'`eval "ls $args"

EDIT: This answer was rewritten to place an example with the least potential for harm, first. Thanks to @CharlesDuffy for the reminder that examples should be secure by default.


Use set to set your variables as positional parameters; then quoting will be preserved if you refer to them via "$@" or "$1", "$2", etc. Make sure to use double quotes around your variable names.

set -- "$f1" "$f2"touch "$@"ls "$@"rm "$@"