abubin
January 17, 2011, 5:12am
1
I have an rsync command that I want to create a variable where user can change to customize the parameters.
complete rsync command to run:
$RSYNC -e 'ssh -ax -o ClearAllForwardings=yes' --log-file=$LOG_FILE --delete -avzcr -u --update $SRC_DIR $USER@$TRG_SRV:$TRG_DIR >> $LOG_FILE
What I want to do is separate our the parameters into a variable:
rsync_param="-e 'ssh -ax -o ClearAllForwardings=yes' --log-file=$LOG_FILE --delete -avzcr -u --update"
Then I modify the rsync to run as below:
$RSYNC $rsync_param $SRC_DIR $USER@$TRG_SRV:$TRG_DIR >> $LOG_FILE
But it doesn't work. I get syntax error. But when I echo out the command, it is same as the original command.
Any idea how to solve this?
wempy
January 17, 2011, 5:48am
2
When you assign the string to the variable $rsync_param it will take the [bold]current[/bold] value of the variable $LOG_FILE, which may or may not be set (you haven't shown any context) so that when rsync comes to run it sees --log-file=
which would be a syntax error.
I've run into this issue when I wrote an man rsync (linux) script, in which I had to man eval (linux) the command to get things to work properly, as in:
eval $RSYNC $rsync_param $SRC_DIR $USER@$TRG_SRV:$TRG_DIR >> $LOG_FILE
To demonstrate what is happening, I created a quick script to display the number of parameters, and the parameters themselves:
#! /bin/sh
echo '#:' ${#}
while [[ 0 -lt ${#} ]]; do echo "${1}"; shift; done | cat -n
And here are the results:
trogdor $ ./countem a b c d
#: 4
1 a
2 b
3 c
4 d
trogdor $ ./countem a 'b c' d
#: 3
1 a
2 b c
3 d
Which is as expected. But if we:
trogdor $ ARGS="a 'b c' d"
trogdor $ ./countem ${ARGS}
#: 4
1 a
2 'b
3 c'
4 d
${ARGS}
is expanded into four tokens. Double-quoting doesn't help either:
trogdor $ ./countem "${ARGS}"
#: 1
1 a 'b c' d
What you need to do is have the shell re-parse your command line, so that it is recognizes the quoting within your variables:
trogdor $ eval ./countem "${ARGS}"
#: 3
1 a
2 b c
3 d
Or without the quotes:
trogdor $ eval ./countem ${ARGS}
#: 3
1 a
2 b c
3 d
Be warned, the script will evaluate the command line twice. Be careful with characters that will cause command line expansion.
1 Like
abubin
January 17, 2011, 11:08pm
4
thanks for the explanation. Now I understand what's the problem and usage of "eval".
I manage to solve the problem by dumping the whole command into another variable and then use eval on that variable.
run_rsync="$RSYNC $rsync_param $SRC_DIR $USER@$TRG_SRV:$TRG_DIR >> $LOG_FILE"
eval $run_rsync
Tested and it seems to be running.
Thanks again for the great help.
Most awsome post mr ludwig. I have been having trouble with understanding what exactly eval was good for. Now I know too.
I would be interested in an example of a situation where this doesn't work as you were warning about.