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)