I'm having some trouble uploading directories(which contain other directories a few levels deep) by sftp. I realize I could work around this by gzipping, but I don't see why that's necessary.

Anyway, I try

sftp> put bin/
Uploading bin/ to /home/earlz/blah/bin
bin/ is not a regular file
sftp> put -r bin/
Uploading bin/ to /home/earlz/blah/bin
Couldn't canonicalise: No such file or directory
Unable to canonicalise path "/home/earlz/blah/bin"

I think the last error message is completely stupid. So the directory doesn't exist? Why not create the directory?

Is there anyway around this issue with sftp, or should I just use scp?

10 Answers 10


CORRECTED: I initially claimed wrongly that OpenSSH did not support put -r. It does, but it does it in a very strange way. It seems to expect the destination directory to already exist, with the same name as the source directory.

sftp> put -r source
 Uploading source/ to /home/myself/source
 Couldn't canonicalize: No such file or directory
sftp> mkdir source
sftp> put -r source
 Uploading source/ to /home/myself/source
 Entering source/

What's especially strange is that this even applies if you give a different name for the destination:

sftp> put -r source dest
 Uploading source/ to /home/myself/dest
 Couldn't canonicalize: ...
sftp> mkdir dest
sftp> put -r source dest
 Uploading source/ to /home/myself/dest/source
 Couldn't canonicalize: ...
sftp> mkdir dest/source
sftp> put -r source dest
 Uploading source/ to /home/myself/dest/source
 Entering source/

For a better-implemented recursive put, you could use the PuTTY psftp command line tool instead. It's in the putty-tools package under Debian (and most likely Ubuntu).

Alternately, Filezilla will do what you want, if you want to use a GUI.

  • FYI: sftp allows put -r from OpenSSH 5.4 – Tino May 3 '16 at 12:04
  • 3
    Thanks -- I've corrected my answer. It's about time, huh? ;-P – Jander May 3 '16 at 23:34

I don't know why sftp does this but you can only recursive copy if the destination directory already exists. So do this...

sftp> mkdir bin
sftp> put -r bin
  • 5
    This is the correct answer! :) – sig11 Jul 29 '14 at 13:52
  • 2
    You really are a useful dude! – justinpage Jul 14 '15 at 23:21
  • it's working for me. thank's @Useful Dude – Laukik Patel Jan 29 '16 at 19:47
  • 1
    -r needs OpenSSH 5.4 or higher – Tino May 3 '16 at 12:06

You might be interested in using rsync instead. The command for that would be

 rsync --delete --rsh=ssh -av bin/ remote-ip-or-fqdn:/home/earlz/blah/bin/

This will copy everything in bin/ and place it in on the remote server in /home/earlz/blah/bin/. As an added benefit, it will first check to see if the file on the remote side hasn't changed, and if it hasn't, it won't re-send it. Additionally, you can add a -z option and it will compress it for you.

  • Awsome! So simple! – Asken Jul 16 '13 at 9:47
  • 3
    Please note that sftp is a command and a protocol. rsync does not support the sftp-protocol. – Tino May 3 '16 at 12:07

May I suggest a somewhat complicated answer, without zipping, but including tar?

Here we go:

tar -cf - ./bin | ssh target.org " ( cd /home/earlz/blah ; tar -xf - ) "

This will pack the directory ./bin with tar (-cf:=create file), filename - (none, stdout) and pipe it through the ssh-command to target.org (which might as well be an IP) where the command in quotes is performed, which is: cd to blah, and tar -xf (extract file) - none, no name, just stdin.

It's as if you pack a package at home, bring it to the post, then drive to work, where you expect the package and open it.

Maybe there is a much more elegant solution which just uses sftp.

  • A piped tar is a very good solution, however this needs ssh login support (sftp is a different protocol on top of ssh). tar, unlike others, by default, runs recursively, transfers all special files (FIFO, block/character devices etc.), tries to translate the UID/GID mapping from the source to the target system and has a traditional short commandline. (One exception though: "Unix domain sockets" are not transferred. But who needs those?) – Tino May 3 '16 at 12:22
  • I use this method when I need compression between nodes also you can use the pv tool to watch speed in long transfers – Felipe Alcacibar May 3 '17 at 14:40

lcd: your local folder (with subfolders)

cd: your remote folder

put -r .

  • actually, I think this is the most correct answer... for the purpose of putting my whole folder there – 太極者無極而生 Jan 27 '16 at 14:21
  • sftp complained when I cd'd into the local parent folder and tried to put the directory by name. But cd'ing into the directory I wanted to upload did it. Thank you! – karimkorun Jul 7 '16 at 10:15

You can use yafc (Yet anoter FTP/SFTP client). The -r option works there very well.



for example :

rsync -zrp /home/a/ user@remote.host.com:/home/b/  

Original answer by Karolos


Login to the remote server with ssh, use sftp to connect back to your box, then use the get -r command to transfer directories to the remote server. The get command allows you to transfer directories recursively without having the directory already created.

ssh remote ip
sftp local ip 
get -r whichever-dir

SFTP case:

I needed to copy that structure on my ftp:

mainfolder --- folder --- subfolder
                  |           |
              file1.txt   file2.txt

That solved my problem:

cd ./mainfolder
mkdir folder
put -r /from/source/folder/* /mainfolder/folder/
cd ./folder
mkdir subfolder
put -r /from/source/folder/subfolder/* /mainfolder/folder/subfolder/

I just learned from the Arch Linux Wiki that it is possible to mount the sftp-share using sshfs. I'm running an sftp-server with chroot and jail and sshfs works very well.

  1. Mount: sshfs <sftpuser>@<server>:<read/writable/directory> <your/local/mount/directory>
  2. Unmount: fusermount -u <your/local/mount/directory>

Your Answer

