Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

A bash script has the following line

    rsync $OPTS $BACKDIR $USER@$DEST:$DESTDIR     

but one of the options is rsh='ssh -p2222' It complains :

    rsync: -p2222': unknown option
    rsync error: syntax or usage error (code 1) at main.c(1425) [client=3.0.7]

But when I change the script to :

    echo rsync $OPTS $BACKDIR $USER@$DEST:$DESTDIR     

and manually run the printed command it works.

Please advise

share|improve this question

4 Answers 4

up vote 5 down vote accepted

Short answer: see BashFAQ #50.

Long answer: Putting commands (or parts of commands) into variables and then getting them back out intact is complicated. When the shell expands a variable on the command line, if the variable was in double-quotes it's not parsed (see @Dennis Williamson's answer); if it was not in quotes, spaces in it are parsed as argument breaks, but quotes and escape are not parsed (which is why you got an error about a literal quote mark in one of the args to rsync). In either case, putting quotes in the variable's value does nothing useful.

There are, however, several ways to fix your script, depending on how complex OPTS is:

  1. If --rsh is the only thing in OPTS, then double-quote it (as in Dennis Williamson's answer):

    OPTS='--rsh=ssh -p2222'
    rsync "$OPTS" "$BACKDIR" "$USER@$DEST:$DESTDIR"
    

    (Note the double-quotes around the other args as well: this is to prevent misparsing if they contain spaces, and is generally good scripting hygiene.)

  2. If the contents of OPTS are constant (or at least, the --rsh part is), then don't try to put it in a variable, just use it directly:

    rsync --rsh='ssh -p2222' $RESTOFOPTS "$BACKDIR" "$USER@$DEST:$DESTDIR"
    
  3. If neither of those simple cases apply, use an array instead of a plain variable:

    OPTS=(-x --delete --inplace)
    if [[ "$rsync_version" == 2.* ]]; then
        OPTS+=(-aE)
    else
        OPTS+=(-aNHX)
    fi
    if [[ -n "$using_rsh" ]]; then
        OPTS+=('--rsh=ssh -p2222')
    fi
    rsync "${OPTS[@]}" "$BACKDIR" "$USER@$DEST:$DESTDIR"
    
share|improve this answer

To preserve the quoting and whitespace in the variable, you need to quote the variable when it's referenced:

rsync "$OPTS" "$BACKDIR" "$USER@$DEST:$DESTDIR"
share|improve this answer

I guess your rsh option should be used with rsync's -e (resp. --rsh) flag so that rsync knows to use the custom port for the ssh connection. Does your command look like so:

ssh -some -opts --rsh="ssh -p222" fromdir/ user@host:/todir

It may be that the quotation marks around the 'ssh -p222' part are simply missing when rsync executes. You could try defining the rsh variable like this instead:

rsh='"ssh -p222"'

so that it evaluates to "ssh -p222" during execution (literally, including the double quotes).

share|improve this answer

One option is to remove "space" from $IFS in your script:

#!/bin/bash
IFS=$'\n\t'
...
rsync $OPTS $BACKDIR $USER@$DEST:$DESTDIR

Bash will then behave as most programmers would expect, since the spaces will no longer be used as field separators within the variables.

share|improve this answer
    
Depending on the script, that may break other things. The correct way to do this is with proper quoting. Bash and other Bourne-derived shells are not the same as other languages. Trying to treat them as such can only lead to difficulty. –  Dennis Williamson Feb 23 '11 at 17:38

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.