118

Several times throughout the day, I may be running a test where I need to look through a log file on a remote server. I've gotten used to using my terminal to sftp into the remote server and pull the desired log file down to /tmp on my local machine.

I was looking through the options today using man sftp in an attempt to figure out a way to run the following commands basically in a single line so that I don't have to type a command, press enter, type a command press enter, etc.

(what I do now)

sftp myuser@myserver
--mypassword at prompt
lcd /tmp
get /dir/dir/dir/dir/file
quit

I found while looking through man sftp a reference to scp which I haven't used before. I feel it may be what I'm looking for, but I didn't see a way to specify where I wanted the securely copied file to go.

Could someone provide me with a way to get /dir/file from a remote server and have it download to /tmp/file_plus-my-description?

I was hoping to be able to run an sftp or scp command similar to a regularUNIX copy like:

scp myuser@myserver /dir/file /tmp/file_plus-my-description

I'm using the built in Terminal in Mac OS X 10.8. Thanks.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Kyle
  • 14,036
  • 11
  • 46
  • 61

7 Answers7

263

Update Sep 2017 - tl;dr

Download a single file from a remote ftp server to your machine:

sftp {user}@{host}:{remoteFileName} {localFileName}

Upload a single file from your machine to a remote ftp server:

sftp {user}@{host}:{remote_dir} <<< $'put {local_file_path}'

Original answer:

Ok, so I feel a little dumb. But I figured it out. I almost had it at the top with:

sftp user@host remoteFile localFile

The only documentation shown in the terminal is this:

sftp [user@]host[:file ...]
sftp [user@]host[:dir[/]]

However, I came across this site which shows the following under the synopsis:

sftp [-vC1 ] [-b batchfile ] [-o ssh_option ] [-s subsystem | sftp_server ] [-B buffer_size ] [-F ssh_config ] [-P sftp_server path ] [-R num_requests ] [-S program ] host 
sftp [[user@]host[:file [file]]] 
sftp [[user@]host[:dir[/]]]

So the simple answer is you just do : after your user and host then the remote file and local filename. Incredibly simple!

Single line, sftp copy remote file:

sftp username@hostname:remoteFileName localFileName
sftp kyle@kylesserver:/tmp/myLogFile.log /tmp/fileNameToUseLocally.log

Update Feb 2016

In case anyone is looking for the command to do the reverse of this and push a file from your local computer to a remote server in one single line sftp command, user @Thariama below posted the solution to accomplish that. Hat tip to them for the extra code.

sftp {user}@{host}:{remote_dir} <<< $'put {local_file_path}'
Kyle
  • 14,036
  • 11
  • 46
  • 61
  • is there a way to copy the file in one single line? – Thariama Feb 11 '16 at 14:33
  • @Thariama I'm not sure what you are asking. The code above shows you how to copy a file from a remote server using sftp to your local machine in one single line. `sftp kyle@kylesserver:/tmp/myLogFile.log /tmp/fileNameToUseLocally.log` – Kyle Feb 11 '16 at 15:25
  • 25
    i was asking the other way around (copy to remote server), but i found it myself: _sftp {user}@{host}:{dir} <<< $'put {path to file}'_ – Thariama Feb 11 '16 at 16:16
  • 2
    My apologies, misunderstood. I'll copy your response into the answer in case it can help someone in the future. Thanks @Thariama – Kyle Feb 11 '16 at 19:56
  • 1
    To complete @Thariama answer, if you want to move to a directory before uploading the file write each command separate by '\n'; ```sftp {user}@{host}:{dir} <<< $'cd web\n put my_file.txt'``` – Snook Jun 16 '17 at 08:12
  • 1
    For us TL:DR -types, it's a bit confusing to have the incorrect solution as the first highlighted row :-) – skoll Sep 21 '17 at 14:21
  • 1
    @Kyle, much better! – skoll Sep 22 '17 at 06:40
  • Why did you use a different syntax for user & host name? username@hostname vs {user}@{host} – jaques-sam Dec 01 '17 at 10:19
  • The second example was provided in the comments by user @Thariama several months after the original post. I just added the data to the original post. No reason, just an oversight. Both seemed to get the point across. – Kyle Dec 01 '17 at 18:51
  • 1
    I find it bizarre that sftp doesn't include an option for uploading a file in a single command. This works fine, but it's much too hacky for such a simple operation. It's still the only thing I can find that actually works out of the box, so thanks. :) – Teekin Dec 26 '17 at 13:53
  • sftp {user}@{host}:{remote_dir} <<< $'put {local_file_path}' only worked on Windows using git bash. Errors shown using '<<<' on command prompt. – Ivan Monteiro Jan 25 '19 at 23:09
  • could you please explain `$'put {local_file_path}'`. i never seen command like that.`$(some command)` is common.@Kyle – Hossein Vatani Sep 22 '21 at 11:39
  • @HosseinVatani it is essentially it's own separate command which is pushed into the sftp and executed after the connection is established. – Kyle Sep 23 '21 at 13:21
  • @HosseinVatani the explanation by Kyle is confusing. It is a normal string `'put ...'` would normally work the same. The `$` at the beginning says that backslash sequences inside the string (like `\n`) will be replaced by special characters (like LF - newline). You need it to separate multiple commands for `sftp`. --- `<<<` is here string redirection which sends the following string to the `stdin` of the command (here `sftp`). --- Both are not part of the POSIX shell! They are extensions for example in bash. IMHO this should be added to the answer. – pabouk - Ukraine stay strong Mar 13 '22 at 22:55
  • I started to use this `sftp` syntax and I have to add that it is much more similar to the `scp` syntax than the answer suggests. So not only the `user@` part can be omitted when not needed (e.g. specified inside `~/.ssh/config` but also the destination name can be a directory. In such a case the remote file si copied with the original file name to the local directory. I think most of the time I will use `.` as the destination. – pabouk - Ukraine stay strong Mar 15 '22 at 12:44
  • Won't work as you're not giving password. – Philip Rego Sep 14 '22 at 18:06
  • @PhilipRego if you don't enter a password, the system will prompt you for a password following your command. Often you don't want to include the password within your command, because you don't want to be leaving passwords laying around in shell command history. – Kyle Sep 15 '22 at 19:39
  • I want it in the command because sftp is not accepting my password. Works fine in WinSCP but failing with sftp command. No special characters. – Philip Rego Sep 15 '22 at 20:49
14

SCP answer

The OP mentioned SCP, so here's that.

As others have pointed out, SFTP is a confusing since the upload syntax is completely different from the download syntax. It gets marginally easier to remember if you use the same form:

echo 'put LOCALPATH REMOTEPATH' | sftp USER@HOST
echo 'get REMOTEPATH LOCALPATH' | sftp USER@HOST

In reality, this is still a mess, and is why people still use "outdated" commands such as SCP:

scp USER@HOST:REMOTEPATH LOCALPATH
scp LOCALPATH USER@HOST:REMOTEPATH

SCP is secure but dated. It has some bugs that will never be fixed, namely crashing if the server's .bash_profile emits a message. However, in terms of usability, the devs were years ahead.

c z
  • 7,726
  • 3
  • 46
  • 59
7

To UPLOAD a single file, you will need to create a bash script. Something like the following should work on OS X if you have sshpass installed.

Usage:

sftpx <password> <user@hostname> <localfile> <remotefile>

Put this script somewhere in your path and call it sftpx:

#!/bin/bash

export RND=`cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32`
export TMPDIR=/tmp/$RND
export FILENAME=$(basename "$4")
export DSTDIR=$(dirname "$4")

mkdir $TMPDIR
cp "$3" $TMPDIR/$FILENAME

export SSHPASS=$1
sshpass -e sftp -oBatchMode=no -b - $2 << !
   lcd $TMPDIR
   cd $DSTDIR
   put $FILENAME
   bye
!

rm $TMPDIR/$FILENAME
rmdir $TMPDIR
sstur
  • 1,769
  • 17
  • 22
  • Thanks for the reply, however, the answer I denoted above will utilize single line command with sftp to get a file from a remote server and save the file to a specific location on your local machine. I have verified that it will work on OS X with only sftp. – Kyle Dec 26 '14 at 17:32
  • 2
    Yes, that is certainly the best answer for transferring from remote to local. However I though I'd add a solution for doing the opposite: local to remote. Just in case it's helpful to anyone. Thanks! – sstur Dec 27 '14 at 18:12
5

Or echo 'put {path to file}' | sftp {user}@{host}:{dir}, which would work in both unix and powershell.

js2010
  • 23,033
  • 6
  • 64
  • 66
  • This syntax also works with puttyftp (psftp). Just thought I’d share since that’s the reason I ended up here – 9 Guy Jun 02 '20 at 04:59
3

sftp supports batch files.

From the man page:

-b batchfile

Batch mode reads a series of commands from an input batchfile instead of stdin.  
Since it lacks user interaction it should be used in conjunction with non-interactive
authentication.  A batchfile of `-' may be used to indicate standard input.  sftp 
will abort if any of the following commands fail: get, put, rename, ln, rm, mkdir, 
chdir, ls, lchdir, chmod, chown, chgrp, lpwd, df, symlink, and lmkdir.  Termination 
on error can be suppressed on a command by command basis by prefixing the command 
with a `-' character (for example, -rm /tmp/blah*).
synthesizerpatel
  • 27,321
  • 5
  • 74
  • 91
  • As this is a process I do several times a day for different files in different places, it would be nice to be able to just memorize a command I could type into a single line in my terminal (which is always open) and press enter. Using `--batch` would require me to put my commands into a file then pass in that file as a param. I'm still playing with `scp`, I feel it may contain my solution. – Kyle May 23 '13 at 19:11
  • Maybe 'expect' is what you're looking for then. http://www.linuxjournal.com/article/3065 – synthesizerpatel May 23 '13 at 19:35
3

OpenSSH scp supports SFTP protocol since 8.7.

Since OpenSSH 9.0 the scp uses SFTP by default.

In 8.7 through 8.9, the SFTP has to be selected via -s parameter.

Download:

scp -s user@host:/remote/source/path /local/target/path

Upload:

scp -s /local/source/path user@host:/remote/target/path
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
2

A minor modification like below worked for me when using it from within perl and system() call:

sftp {user}@{host} <<< $'put {local_file_path} {remote_file_path}'
user2443447
  • 151
  • 1
  • 8