SSH invokes a shell on the server (there's no way to bypass that). Scp calls this shell and tells it the names of the files that need to be written. The way scp is designed is to interpolate whatever you pass as a file name directly into the remote shell command. This means that if you have any shell special characters in file names, which for typical Unix shells means whitespace and !"#$&'()*-;<=>?@[\]^`{|}~
(some of these depend on the shell and position in the name), you need to quote them twice: once for the local shell and once for the remote shell.
This has advantages, in particular it allows you to specify wildcards. It's also what lets you use ~
for the remote home directory (but file names are relative to the remote home directory, so you could just use [email protected]:download/…
instead of [email protected]:~/download/…
). But the downside is that you need to take care when the file names do contain special characters. You also need to take care if you want to filter allowed file names on the server (especially for a restricted account that doesn't have shell command privileges).
The easy way of quoting twice is to use single quotes around the whole name, and a backslash before every special character that needs to be protected on the remote side. That doesn't work for single quotes in the file name; escape those as the four characters'\''
. In your example:
scp '[email protected]:download/file\ that\ have\ spaces.txt' ~/download/
Your attempt with two backslashes didn't work because \\
is parsed by the local shell as backslash followed by a space that separates arguments; you need to send backslash-space to the remote host, and both the backslash and the space need to be protected from parsing by the local shell, so both need a backslash before them, i.e. you need 3 backslashes and a space.
scp [email protected]:download/file\\\ that\\\ have\\\ spaces.txt ~/download/
SFTP doesn't go through a shell, so it's a way to avoid problems with special characters. SSHFS builds on SFTP and provides direct remote file access, so you can do
mkdir remote
sshfs [email protected]: remote
cp remote/download/file\ that\ have\ spaces.txt ~/download/
fusermount -u remote
rmdir remote