Bash Pass Variable as Argument with Quotes

Bash pass variable as argument with quotes

I don't know where you got program from, but it appears that it's broken. Here's a correct way to write it in bash:

#!/bin/bash

for arg in "$@"; do
echo "$arg"
done

This will print each argument in a separate line to make them easier to distinguish (it will of course have a problem with arguments that contain a line break, but we will not pass such an argument).

After you have saved the above as program and gave it the execute permission, try this:

$ args='"Hello there"'
$ ./program "${args}"
"Hello there"

whereas

$ args='"Hello there"'
$ ./program ${args}
"Hello
there"

How to quotes in bash function parameters?

The reason this happens is because bash interprets the arguments, as you thought. The quotes simply aren't there any more when it calls the function, so this isn't possible. It worked in DOS because programs could interpret the command line themselves, not that it helps you!

How do I pass on script arguments that contain quotes/spaces?

Use "$@" with quotes:

prog="$1"
"$@"
ecode="$?"
echo "$prog exited with $ecode"

This will pass each argument exactly as it was received. If you don't include the quotes, each element will be split according to $IFS:

  • "$@" is like "$1" "$2" "$3" ..., passing each element as a separate argument.
  • "$*" is like "$1 $2 $3 ...", passing all elements concatenated as a single argument
  • $* and $@ is like $1 $2 $3 ..., breaking up each element on whitespace, expanding all globs, and passing each resulting word as a separate element ($IFS).

The same is true for arrays, such as "${array[@]}" and "${array[*]}"

how to pass variable value with double quote in shell script

When you use single quotes, it causes the shell to preserve the literal value of each character within the quotes. This means the $ will be treated as a literal $ character.

You should use double quotes:

USER_UID="$1"
echo "generate_token(\"$USER_UID\")"

From the bash man page, under the Quoting section:

Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !.

For POSIX details on quoting, see here.

Example in an interactive shell:

$ USER_UID='foo'
$ echo "generate_token(\"$USER_UID\")"
generate_token("foo")

This will also work if USER_UID contains spaces:

$ USER_UID='var with spaces'
$ echo "generate_token(\"$USER_UID\")"
generate_token("var with spaces")

How can I preserve quotes in printing a bash script's arguments

The quotes are removed before the arguments are passed to your script, so it's too late to preserve them. What you can do is preserve their effect when passing the arguments to the inner command, and reconstruct an equivalent quoted/escaped version of the arguments for printing.

For passing the arguments to the inner command "$@" -- with the double-quotes, $@ preserves the original word breaks, meaning that the inner command receives exactly the same argument list that your script did.

For printing, you can use the %q format in bash's printf command to reconstruct the quoting. Note that this won't always reconstruct the original quoting, but will construct an equivalent quoted/escaped string. For example, if you passed the argument 'uptime ; uname -a' it might print uptime\ \;\ uname\ -a or "uptime ; uname -a" or any other equivalent (see @William Pursell's answer for similar examples).

Here's an example of using these:

printf "Running command:"
printf " %q" innercmd "$@" # note the space before %q -- this inserts spaces between arguments
printf "\n"
innercmd "$@"

If you have bash version 4.4 or later, you can use the @Q modifier on parameter expansions to add quoting. This tends to prefer using single-quotes (as opposed to printf %q's preference for escapes). You can combine this with $* to get a reasonable result:

echo "Running command: innercmd ${*@Q}"
innercmd "$@"

Note that $* mashes all arguments together into a single string with whitespace between them, which is normally not useful, but in this case each argument is individually quoted so the result is actually what you (probably) want. (Well, unless you changed IFS, in which case the "whitespace" between arguments will be the first character of $IFS, which may not be what you want.)

bash: How to warp interpolated variable in quotes to pass it (together with quotes) as argument to another command in script

The argument that the docker binary sees will contain only the double quotes.

The single quotes are added by the set -x mechanism only for the purpose of showing you what is in the argument list.


I suspect you don't actually want docker to see any of the quotes. In that case, don't escape them in your command, and instead do

docker run -e "$env" some_image

Double quotes in that position means that if the value of $env contains spaces, it will still be passed to docker as a single argument (with spaces in it), rather than being split into several argument (which would confuse it).

These two commands will produce exactly the same argument array in the new process:

docker run -e VAR=val some_image
docker run -e "VAR=val" some_image

In the second of these cases the double quotes are interpreted by the shell (even though they are not necessary because the argument doesn't contain spaces), and what docker sees in both cases is just the string VAR=val.

If you try something like

env="VAR=multiple words"
set +x
docker run -r "$env" some_image

the third command-line argument to docker will be the spaceful string VAR=multiple words, and this get printed by set -x as something like

+ docker run -r 'VAR=multiple words' some_image

because the print-the-command-line-before-executing code can see it would be confusing not to quote this spaceful string. Again the docker command doesn't see any quotes at all in this invocation.


For debugging these things it can be useful to replace the actual command you're starting with echo. This will print the raw arguments the command sees, without adding any quoting of its own. The downside of this is that you won't be able to tell the difference between a space that is part of a single argument and the space that echo prints by itself between the arguments.



Related Topics



Leave a reply



Submit