Reputation: 315
I would like to use custom identity file when using rsync, but only if the file exists, otherwise I don't want to bother with custom ssh command for rsync. I am having problems with quotes. See examples.
Desired command if identity file exists
rsync -e "ssh -i '/tmp/id_rsa'" /tmp/dir/ u@h:/tmp/dir
Desired command if identity file does not exist
rsync /tmp/dir/ u@h:/tmp/dir
I wanted to create a variable that would contain -e "ssh -i '/tmp/id_rsa'"
and use it as follows
rsync ${identityArg} /tmp/dir/ u@h:/tmp/dir
This variable would be either empty or contain desired ssh command.
An example way I fill the variable (I have tried many ways)
IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
identityArg="-e 'ssh -i \"${IDENTITY_FILE}\"'"
fi
The problem is that quotes are always wrong in the command and I end up with commands similar to these ones (set -x
is set in the script and this is the output)
rsync -e '\ssh' -i '"/tmp/id_rsa"'\''' /tmp/dir/ u@h:/tmp/dir
There is something I do not get about quotation in bash. If you have any good resource about usage of single and double quotes in bash script I would like to read it.
Upvotes: 1
Views: 218
Reputation: 14491
Trying to properly escape quotes is tricky. Better to try to leverage existing constructs. Few alternatives, depending on the situations
If the name of the identity file only contain simple characters (no spaces, wildcard, etc.) consider not wrapping it in quotes. In this case, you can
IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
identityArg="-e 'ssh -i ${IDENTITY_FILE}'"
fi
...
rsync $identityArg ...
Another option is to always pass in the command (ssh or 'ssh -I ...'). This will automatically take care for special characters in the identity file.
IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
identityArg="-i '${IDENTITY_FILE}'"
fi
rsync -e "ssh $identityArg" ...
Third alternative is to use array to create the arguments to rsync
, and let the shell escape the characters as needed. This will allow any character in the identity file.
IDENTITY_FILE="/tmp/id_rsa"
if [ -f "${IDENTITY_FILE}" ]; then
identityArg=(-e "ssh -i '${IDENTITY_FILE}'")
fi
rsync "${identityArg[@]}" ...
Upvotes: 0
Reputation: 7317
Try like this
id=/tmp/id_rsa
[[ -e $id ]] && o1='-e' o2="ssh -i '$id'"
echo $o1 "$o2" /tmp/dir/ u@h:/tmp/dir
Upvotes: 0
Reputation: 52536
You want to add two positional parameters: -e
and ssh -i '/tmp/id_rsa'
, where /tmp/id_rsa
is an expanded variable. You should use an array for this:
args=(/tmp/dir/ u@h:/tmp/dir)
idfile=/tmp/id_rsa
# Let [[ ... ]] do the quoting
if [[ -f $idfile ]]; then
# Prepend two parameters to args array
args=(-e "ssh -i '$idfile'" "${args[@]}")
fi
rsync "${args[@]}"
I'm not convinced the inner single quotes are necessary for ssh -i
, but this expands to exactly the commands shown in the question.
Upvotes: 2