Search code examples
bashrsync

Optionally pass an argument in a bash script


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.


Solution

  • 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.