0
RSYNC="rsync -avzhe 'ssh -i /path/to/deploy_keys/id_rsa' --delete "

# Files
$RSYNC deploy@ip:/var/www/path1 /var/www/path1
$RSYNC deploy@ip:/var/www/path2 /var/www/path2

I'd like to introduce this RSYNC Variable to be more compact, but it throws an error:

Unexpected remote arg: deploy@ip:/var/www/path1

If i use only rsync inside the doublequotes, it works fine. For the sake of readability, i'd keep them separate command invocations.

Aron Novak
  • 314
  • 1
  • 14

3 Answers3

3

I agree that eval is dangerous. In addition to the array approach @Eugeniu Rosca suggested, you could also use a shell function:

my_rsync() {
    rsync -avzhe 'ssh -i /path/to/deploy_keys/id_rsa' --delete "$@"
}

my_rsync deploy@ip:/var/www/path1 /var/www/path1
my_rsync deploy@ip:/var/www/path2 /var/www/path2

BTW, you should read BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!.

Gordon Davisson
  • 107,068
  • 14
  • 108
  • 138
2

If you want to store the command string into a variable and evaluate it later, you can use eval or an alternative safer technique:

#!/bin/bash

# Store the command into an array
RSYNC=(rsync -avzhe 'ssh -i /path/to/deploy_keys/id_rsa' --delete)
# Run the command
"${RSYNC[@]}" deploy@ip:/var/www/path1 /var/www/path1

Why eval should be avoided

Community
  • 1
  • 1
Eugeniu Rosca
  • 5,127
  • 14
  • 43
1

After you assign a string to a variable and then submit it to shell again it is tokenized differently. Consider the following script

VAR="/bin/ls 'Test1 Test2'"
$VAR

It will throw two errors:

/bin/ls: cannot access 'Test1
/bin/ls: cannot access Test2'

You guessed it right, the apostrophes are no longer affecting tokenization. Instead they are treated as normal characters when the commandline arguments are fed to /bin/ls

While eval is rightly considered evil, it is by far the easiest way to get a script running. It stitches all the arguments into one line and applies the tokenizing procedure again.

RSYNC="rsync -avzhe 'ssh -i /path/to/deploy_keys/id_rsa' --delete "

# Files
eval $RSYNC deploy@ip:/var/www/path1 /var/www/path1
eval $RSYNC deploy@ip:/var/www/path2 /var/www/path2
Dmitri Chubarov
  • 14,705
  • 5
  • 36
  • 70