Reputation: 715
I have a command stored in a variable, which I then run:
[root@cxpxwly01wel001 init.d]# cat test
#!/bin/bash
command="su - root -c 'java -Xms16m -the_rest_of_my_java_command'"
echo $command
$command
[root@cxpxwly01wel001 init.d]# ./test
su - root -c 'java -Xms16m -the_rest_of_my_java_command'
su: invalid option -- 'X'
Try `su --help' for more information.
The su error is what you get if the single quotes aren't there:
[root@cxpxwly01wel001 init.d]# su - root -c java -Xms16m -the_rest_of_my_java_command
su: invalid option -- 'X'
Try `su --help' for more information.
With the single quotes there the command works as expected:
[root@cxpxwly01wel001 init.d]# su - root -c 'java -Xms16m -the_rest_of_my_java_command'
-bash: java: command not found
Which suggests to me that when running the variable as a command the single quotes aren't preserved. How do I preserve them?
Note: I'm editing an existing script (inserting the su - around the java command), so I'd like to change as little as possible to keep it close to the source.
Let me add the output when run with set -x
:
+ command='su - root -c '\''java -Xms16m -the_rest_of_my_java_command'\'''
+ echo su - root -c ''\''java' -Xms16m '-the_rest_of_my_java_command'\'''
su - root -c 'java -Xms16m -the_rest_of_my_java_command'
+ su - root -c ''\''java' -Xms16m '-the_rest_of_my_java_command'\'''
su: invalid option -- 'X'
Usage: su [options] [LOGIN]
Options:
-c, --command COMMAND pass COMMAND to the invoked shell
-h, --help display this help message and exit
-, -l, --login make the shell a login shell
-m, -p,
--preserve-environment do not reset environment variables, and
keep the same shell
-s, --shell SHELL use SHELL instead of the default in passwd
Upvotes: 3
Views: 455
Reputation: 6995
The technique I use to avoid the "quoting inside quotes" issues is to build the command in an array. For instance, instead of :
command="su - root -c 'java -Xms16m -the_rest_of_my_java_command'"
I would use :
declare -a command=(su - root -c 'java -Xms16m -the_rest_of_my_java_command')
You can still echo the command (with an array expansion) :
echo "${command[@]}"
Or run it :
"${command[@]}"
The double quotes around the array expansion are important : they tell the shell to expand items without doing any word splitting, so an item containing whitespace will keep its identity as a single string.
By doing it this way, the last argument, which is inside quotes, will remain a single string, and the su
command will not see -Xms16m
as an (invalid) option.
As an aside, the [@]
in "${command[@]}"
means "all elements in the array". Whereas, in an expression like "${command[1]}"
, [1]
would mean "only element at index 1".
Upvotes: 1