I'm trying to write a Bash script that uploads a file to a server. How can I achieve this? Is a Bash script the right thing to use for this?
-
1The solution is not for ftp protocole but for ssh. – hanoo Apr 01 '15 at 02:14
-
The accepted solution includes both ftp and ssh. – greggles Dec 13 '22 at 03:08
11 Answers
Below are two answers. First is a suggestion to use a more secure/flexible solution like ssh/scp/sftp. Second is an explanation of how to run ftp in batch mode.
A secure solution:
You really should use SSH/SCP/SFTP for this rather than FTP. SSH/SCP have the benefits of being more secure and working with public/private keys which allows it to run without a username or password.
You can send a single file:
scp <file to upload> <username>@<hostname>:<destination path>
Or a whole directory:
scp -r <directory to upload> <username>@<hostname>:<destination path>
For more details on setting up keys and moving files to the server with RSYNC, which is useful if you have a lot of files to move, or if you sometimes get just one new file among a set of random files, take a look at:
http://troy.jdmz.net/rsync/index.html
You can also execute a single command after sshing into a server:
From man ssh
ssh [...snipped...] hostname [command] If command is specified, it is executed on the remote host instead of a login shell.
So, an example command is:
ssh username@hostname.example bunzip file_just_sent.bz2
If you can use SFTP with keys to gain the benefit of a secured connection, there are two tricks I've used to execute commands.
First, you can pass commands using echo and pipe
echo "put files*.xml" | sftp -p -i ~/.ssh/key_name username@hostname.example
You can also use a batchfile with the -b
parameter:
sftp -b batchfile.txt ~/.ssh/key_name username@hostname.example
An FTP solution, if you really need it:
If you understand that FTP is insecure and more limited and you really really want to script it...
There's a great article on this at http://www.stratigery.com/scripting.ftp.html
#!/bin/sh
HOST='ftp.example.com'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'
ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
binary
put $FILE
quit
END_SCRIPT
exit 0
The -n
to ftp ensures that the command won't try to get the password from the current terminal. The other fancy part is the use of a heredoc: the <<END_SCRIPT
starts the heredoc and then that exact same END_SCRIPT
on the beginning of the line by itself ends the heredoc. The binary
command will set it to binary mode which helps if you are transferring something other than a text file.
-
I would like to do this! Can you please expand on how I can do this? I need to do some things with ssh after uploading the file. Can this be done in one session? – Andrew Dec 12 '09 at 21:46
-
17While it was useful advice for the OP, it shouldn't be the accepted answer. It doesn't answer the original question (that is found via Google) – Lukas Eder Apr 14 '15 at 10:29
-
2Some of the other posters have added binary mode (i.e. `bin`) to the FTP commands. Since yours is the accepted answer, I recommend you adding this to your answer too. – Stephen Quan Feb 10 '17 at 00:12
-
Thanks for the answer including both ssh and FTP. I don't understand the fuss about FTP. Maybe I'm working for a client who's website is on FTP and I just don't care, I care only about what the client wants to have done with his website. – Maciej Krawczyk Jul 10 '18 at 18:18
-
1Can also type `hash` to show progress of the ftp transmission in a way. Also, you will usually see `<
– AdamKalisz Dec 12 '18 at 07:33 -
If you need to upload to **another port**, use `scp -P 22
@ : ` (change 22 to the port you need) -
-
-
-
1@SayanDasgupta as the answer says "The binary command will set it to binary mode which helps if you are transferring something other than a text file." If you are transferring images, pdfs, documents, zips, archives you want binary mode. If you know you are only transferring literal text files (e.g. source code, csvs) then skipping the binary might save you a tiny amount of time. – greggles Dec 13 '22 at 03:07
You can use a heredoc to do this, e.g.
ftp -n $Server <<End-Of-Session
# -n option disables auto-logon
user anonymous "$Password"
binary
cd $Directory
put "$Filename.lsm"
put "$Filename.tar.gz"
bye
End-Of-Session
so the ftp
process is fed on standard input with everything up to End-Of-Session
. It is a useful tip for spawning any process, not just ftp
! Note that this saves spawning a separate process (echo, cat, etc.). It is not a major resource saving, but it is worth bearing in mind.

- 30,738
- 21
- 105
- 131

- 268,207
- 37
- 334
- 440
-
This is totally confusing. How do I get out of this End-Of-Session thing? Why not input directly to the ftp prompt that comes without that? – erikbstack Aug 26 '15 at 09:53
-
2@erikb85 - this for scripts, not (necessarily) for interactive use. The heredoc will automatically register an act upon your 'End-Of-Session' marker (you'd likely use EOF or similar) – Brian Agnew Aug 26 '15 at 13:07
The ftp
command isn't designed for scripts, so controlling it is awkward, and getting its exit status is even more awkward.
Curl is made to be scriptable, and also has the merit that you can easily switch to other protocols later by just modifying the URL. If you put your FTP credentials in your .netrc, you can simply do:
# Download file
curl --netrc --remote-name ftp://ftp.example.com/file.bin
# Upload file
curl --netrc --upload-file file.bin ftp://ftp.example.com/
If you must, you can specify username and password directly on the command line using --user username:password
instead of --netrc
.

- 970
- 8
- 10
-
3
-
`curl` is not installed by default on [Ubuntu MATE 20.04](https://en.wikipedia.org/wiki/Ubuntu_MATE#Releases) (Focal Fossa). (But neither is [lftp](https://en.wikipedia.org/wiki/Lftp).) – Peter Mortensen Jul 25 '21 at 09:07
Install ncftpput and ncftpget. They're usually part of the same package.

- 179,021
- 58
- 319
- 408
-
2command line is: "ncftpput -u username -p password server.org /path/ filename.blah" note that the connection won't be encrypted and the password will be sent in plain text. – Adam Mar 12 '16 at 13:19
-
4@Adam the "connection won't be encrypted" etc is a consequence of using FTP, which was specified in the question. It's going to happen no matter what FTP client you use. – Paul Tomblin Mar 14 '16 at 01:21
The command in one line:
ftp -in -u ftp://username:password@servername/path/to/ localfile

- 30,738
- 21
- 105
- 131

- 113
- 1
- 1
-
2@erikbwork -u is: " -u URL file [...] - Upload files on the command line to URL where URL is one of the ftp URL types as supported by auto-fetch (with an optional target filename for single file uploads), and file is one or more local files to be uploaded." – schmilblick Aug 18 '17 at 06:14
-
7
Use this to upload a file to a remote location:
#!/bin/bash
#$1 is the file name
#usage:this_script <filename>
HOST='your host'
USER="your user"
PASSWD="pass"
FILE="abc.php"
REMOTEPATH='/html'
ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
cd $REMOTEPATH
put $FILE
quit
END_SCRIPT
exit 0

- 30,738
- 21
- 105
- 131

- 613
- 6
- 9
-
1This is a fairly late answer to not be using .netrc, it is however extendable to delete and gets many of us out of the wput/wget/wdel segmentation violation hole. – mckenzm Jul 22 '18 at 09:41
-
-
An explanation would be in order. For example, how is it different from previous answers? – Peter Mortensen Jul 25 '21 at 09:01
#/bin/bash
# $1 is the file name
# usage: this_script <filename>
IP_address="xx.xxx.xx.xx"
username="username"
domain=my.ftp.domain
password=password
echo "
verbose
open $IP_address
USER $username $password
put $1
bye
" | ftp -n > ftp_$$.log

- 46,381
- 14
- 112
- 137
-
5
-
2At the moment this writes to a file 'ftp' and doesn't spawn an ftp process – Brian Agnew Dec 12 '09 at 19:25
-
2
-
@ennuikiller: You have spaces around equal signs that Bash doesn't like. Also, hardcoding passwords in cleartext is a bad idea. – Dennis Williamson Dec 12 '09 at 19:30
-
There isn't any need to complicate stuff. This should work:
#/bin/bash
echo "
verbose
open ftp.mydomain.net
user myusername mypassword
ascii
put textfile1
put textfile2
bin
put binaryfile1
put binaryfile2
bye
" | ftp -n > ftp_$$.log
Or you can use mput if you have many files...

- 70,800
- 18
- 132
- 147

- 41
- 3
Working example to put your file on root...see, it's very simple:
#!/bin/sh
HOST='ftp.users.qwest.net'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'
ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
put $FILE
quit
END_SCRIPT
exit 0

- 30,738
- 21
- 105
- 131

- 613
- 6
- 9
-
#!/bin/bash #$1 is the file name #usage:this_script
HOST='yourhost' USER="youruser" PASSWD="yourpass" FILE="abc.php" REMOTEPATH='/html' ftp -n $HOST < – Shal Apr 29 '15 at 07:27
If you want to use it inside a 'for' to copy the last generated files for an everyday backup...
j=0
var="`find /backup/path/ -name 'something*' -type f -mtime -1`"
# We have some files in $var with last day change date
for i in $var
do
j=$(( $j + 1 ))
dirname="`dirname $i`"
filename="`basename $i`"
/usr/bin/ftp -in >> /tmp/ftp.good 2>> /tmp/ftp.bad << EOF
open 123.456.789.012
user user_name passwd
bin
lcd $dirname
put $filename
quit
EOF # End of ftp
done # End of 'for' iteration

- 30,738
- 21
- 105
- 131

- 19
- 7
echo -e "open <ftp.hostname>\nuser <username> <password>\nbinary\nmkdir New_Folder\nquit" | ftp -nv

- 30,738
- 21
- 105
- 131
-
2An explanation would be in order. For example, what is the idea/gist? – Peter Mortensen Jul 25 '21 at 09:03