Shell Script: FTP File Transfer

Objective: Use a shell script to upload or download a file via FTP.

FTP client programs typically read the password from a tty (eg. keyboard) device. To automate the FTP process, we will need to perform some redirection. Below is a simple shell script that does a file upload to a FTP server.

The lines between <<EOF and EOF are FTP commands. The last FTP command is a bye command that will close the FTP connection.

To do a file download instead of a upload, simply change the put command to a get command and other commands as necessary.

The problem with this script is that it is not that easy to determine if the file has been transferred successfully. The exit status of FTP client programs usually return 0 whether or not the transfer is successful.

To determine if a file transfer is successful, I usually redirect the output of the ftp program and look for FTP server return code of 226. Note that this might not be a foolproof method. Make sure that you test it before using it. The modified shell script is below.

The improved script above has 2 functions: transfer_ok and transfer_nok. If One of them will be called depending on the contents of the ftp command output. I would say that this is also not a foolproof method – the FTP server can send a 226 reply in response to a FTP abort command as well. But in such scenarios, typically the FTP server will send a 426 (Connection closed; transfer aborted) reply first followed by a 226 reply. Another way to verify that a file transfer is successful is to transfer the file back and check the md5sum of the file.

$ ./ftpcopy.sh
transfer ok

$ cat ftp.log
user user password
verbose
Verbose mode on.
cd /remote/upload/directory/path
250 CWD command successful
put foo.bar
200 PORT command successful
150 Opening BINARY mode data connection for foo.bar
226 Transfer complete
11 bytes sent in 0.00018 seconds (61111 bytes/s)
bye
221 Goodbye. 
$ ./ftpcopy.sh
transfer not ok

$ cat  ftp.log
user user password
verbose
Verbose mode on.
cd /remote/upload/directory/path
put foo.bar
200 PORT command successful
550 foo.bar: Operation not permitted
bye
221 Goodbye. 

An alternative and better method is to use the lftp command instead of the ftp command in the shell script. If you are on Linux and if lftp is not installed, install the lftp package using your default package manager.

# on Debian based Linux distributions
$ sudo apt-get install lftp
# on RedHat based Linux distributions
$ sudo yum install lftp

lftp seems to be a bit better than ftp when it comes to exit status codes. There have been cases where people have complained that lftp will return an exit status of 0 even if a non-existing file is requested to be transferred, but I have never encountered such issues. Again, make sure you test all possible scenarios under your environment before using it.

ibrahim = { interested_in(unix, linux, android, open_source, reverse_engineering); coding(c, shell, perl, php, python, java, javascript, nodejs, angular, react); plays_on(xbox, ps4); linux_desktop_user(true); }