Quoting in a bash variable assignment
Using the following simplified code extract:
DIR='a b'
mount_command="./mount.cpfs $loop $DIR -f $OPTS"
sudo $mount_command
Executes this line when trace is on:
+ sudo ./mount.cpfs /dev/loop0 a b -f -o default_permissions,allow_other,attr_timeout=0
But DIR
is not quoted, and so a
and b
are passed as different parameters, rather than the same to ./mount.cpfs
.
What's the best way to go about creating a command sequence like this, and then expanding it into a later command line?
Please keep in mind the code example is simplified to the core problem, I'm using mount_command
in开发者_JAVA技巧 several places with various additions before and after it, and DIR
is passed in by the user. I've tried several combinations of quoting DIR
when assigning to mount_command
, and a primitive attempt at using an array.
Example Usage of mount_command
mount_command="./mount.cpfs $loop $DIR -f $OPTS"
case "$MODE" in
gdb)
sudo gdb -return-child-result -x gdbbatch \
--args $mount_command
;;
normal)
sudo $mount_command
;;
valgrind)
sudo valgrind --track-fds=yes --leak-check=full --malloc-fill=0x80 \
--free-fill=0xff $mount_command
;;
*)
echo "Mode '$MODE' unknown"
mounted=''
exit 2
;;
esac
Update0
Please test your suggestions, I don't think the solution is straightforward.
The best way in bash is to use an array. The array will keep words separated that are meant to be separated and keep spaces inside individual words:
DIR='a b'
mount_command=(./mount.cpfs $loop "$DIR" -f $OPTS)
sudo "${mount_command[@]}"
When "${mount_command[@]}"
is expanded, each element is expanded as a single argument to sudo
even if it has spaces.
Note how I quoted "$DIR"
but not $OPTS
, as your $OPTS
contains multiple words intended to be passed to the mount command as separate words but $DIR
should be kept together. However, you could make OPTS an array in the same way as mount_command
and expand it inside the mount_command
definition as "${OPTS[@]}"
:
DIR='a b'
OPTS=(-o default_permissions,allow_other,attr_timeout=0)
mount_command=(./mount.cpfs $loop "$DIR" -f "${OPTS[@]}")
sudo "${mount_command[@])"
Having done lots of building of commands in bash scripts, I find arrays to be far superior to trying to figure out the correct quoting (if possible) to maintain the command in a simple string.
Try using eval.
Given the following script, called test:
#!/bin/bash
# test
echo $1
If I do this:
DIR='a b'
CMD=."/test \"$DIR\""
eval $CMD
It outputs
a b
See this question
DIR='a b'
OPTS='-o allow_other,attr_timeout=0'
mount_command="./mount.cpfs '$loop' '$DIR' -f '$OPTS'"
eval sudo $mount_command
This should work. It's hard to understand quoting in shell because it's much different than in other languages.
In you case you need to quote '$DIR' variable (and better all which can contains spaces). This is clear. But shell interpret strings just one time! You need to instruct it to reinterpret by using command eval. Without eval, variable $mount_command is expanded but quoting inside is not processed.
You can read my short article about this: White Shell
Try
mount_command="./mount.cpfs $loop \"$DIR\" -f $OPTS"
Try this instead:
DIR='a b'
#following line replaces space occurrences with "\ "
DIR=`echo $DIR | replace ' ' '\ '`
mount_command="./mount.cpfs $loop $DIR -f $OPTS"
sudo $mount_command
精彩评论