3

I'm trying to move a file with rsync to a remote location,

The file has be be named : DRRS_(H264).mp4

but when I try :

rsync -azR output.mp4 [email protected]:encoded/somepath/DRRS_(H264).mp4

it says : bash: syntax error near unexpected token `('

But I don't get how I'm supposed to encapsulate this.

I tried :

rsync -azR output.mp4 [email protected]:"encoded/somepath/DRRS_(H264).mp4"

and

rsync -azR output.mp4 "[email protected]:encoded/somepath/DRRS_(H264).mp4"

without success.

0

3 Answers 3

8

You want to use the -s|--protect-args option to rsync.

Without it, the part after the : is passed as is to the remote shell so you can use constructs of that shell to build the list to transfer.

That way, if you know the remote shell is zsh for instance, you can do:

rsync host:'*(.)' there

to transfer only regular files. Or with csh/bash/zsh/ksh:

rsync host:'{foo,bar}.txt' there

Or:

rsync file 'host:"$HOME/$(uname)-file"'

Now, that means you can't easily transfer files with arbitrary name.

With -s, rsync doesn't pass the string to the remote shell. Instead, it passes it in-band to the rsync server on the remote host, so there's no interpretation by the remote shell.

( and ) being special for most shells, you'd have to escape it using the syntax of the remote shell, and that varies from shell to shell.

Best is to use -s instead.

rsync -sazR output.mp4 [email protected]:'encoded/somepath/DRRS_(H264).mp4'

However, rsync still performs (its own) globbing on the string you pass (even for the destination!). So you still can't pass arbitrary file names with rsync. If you want to process a file called * for instance, you need to escape it with backslash (at least, this time, that's irrespective of the remote shell).

rsync -sazR output.mp4 [email protected]:'\*'

So, to transfer a file with an arbitrary name contained in $1, you'll want to use:

file=$1
rsync_escaped_file=$(
  printf '%s.\n' "$file" | sed 's/[[*?]/\\&/g'
)
rsync_escaped_file=${rsync_escaped_file%.}
rsync -s ... "user@host:$rsync_escaped_file"

If your local shell is bash and you know the login shell of the remote user is also bash of the same version, alternatively, you can use printf %q to escape the characters that are special to the remote shell and not use -s:

LC_ALL=C printf -v shell_escaped_file %q "$1"
rsync ... "user@host:$shell_escaped_file"

If you know the login shell of the remote host is Bourne-like (Bourne, ksh, yash, zsh, bash, ash...) and your ssh client and server allows passing LC_* environment variables, you can also do (again, without -s):

LC_FILE=$1 rsync ... 'user@host:"$LC_FILE"'

Note1: the -s|--protect-args option is only available in version 3.0.0 (2008) or above

Note2: the rsync documentation warns that -s|--protect-args may become the default in future versions of rsync (so to be future-proof, you may want to start using --no-protect-args if you don't want its effect)

3

Try the below one, I tested this and it is working. You should quote your destination path with ' or " and you should escape the ( and ).

rsync -azR output.mp4 [email protected]:'encoded/somepath/DRRS_\(H264\).mp4'

UPDATE:

Call your script as below,

./sample.sh "encoded/somepath/DRRS_\(H264\).mp4"

sample.sh

 #!/bin/bash
 rsync -azR output.mp4 [email protected]:"$1"
3
  • somepath/DRRS_(H264).mp4 is inside $1 is there a way in bash to automatically escape? Jul 21, 2015 at 12:06
  • @VincentDuprez : Please find the updated answer and please do edit your question too.
    – Thushi
    Jul 21, 2015 at 12:15
  • Note that it assumes the login shell of user on server.com is Bourne/csh/fish-like. It won't work if the login shell is rc for instance where backslash is not a quoting character. Best is to use -s|--protect-args instead here. Jul 21, 2015 at 12:29
2

You need to both quote the path and use a backslash to escape parentheses in the remote path.

Either single or double quotes will work.

rsync -azR output.mp4 [email protected]:"encoded/somepath/DRRS_\(H264\).mp4"

OR

rsync -azR output.mp4 [email protected]:'encoded/somepath/DRRS_\(H264\).mp4'

2
  • somepath/DRRS_(H264).mp4 is inside $1 is there a way in bash to automatically escape? Jul 21, 2015 at 12:06
  • That will only work if the login shell of the user on the remote host understands backslash as a quoting operator. Which will be the case in the majority of the cases, but would not be for instance if that shell is rc where the only quoting operator is single quote. Best is to use -s|--protect-args here to have a shell-agnostic solution. Jul 21, 2015 at 12:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .