FTP is a notoriously insecure protocol, but sometimes you just need to get a file from point A to point B and SFTP or SCP aren’t an option. Bash scripting can automate this process, making it a bit less painful.
#!/bin/bash
# Configuration
FTP_HOST="ftp.example.com"
FTP_USER="anonymous"
FTP_PASS="your_email@example.com" # Use a real email for anonymous, or a specific user's credentials
REMOTE_DIR="/pub/incoming"
LOCAL_DIR="/home/user/uploads"
FILENAME="data_$(date +%Y%m%d_%H%M%S).txt"
REMOTE_FILE="$REMOTE_DIR/$FILENAME"
LOCAL_FILE="$LOCAL_DIR/$FILENAME"
# Create local file (example: generate some data)
echo "This is sample data for transfer on $(date)" > "$LOCAL_FILE"
echo "Generated local file: $LOCAL_FILE"
# Check if local file exists
if [ ! -f "$LOCAL_FILE" ]; then
echo "Error: Local file '$LOCAL_FILE' not found."
exit 1
fi
# FTP Transfer using a "here document"
ftp -inv "$FTP_HOST" <<EOF
user $FTP_USER $FTP_PASS
binary
prompt off
cd "$REMOTE_DIR"
put "$LOCAL_FILE" "$FILENAME"
quit
EOF
# Check FTP exit status
if [ $? -eq 0 ]; then
echo "FTP transfer successful!"
echo "Uploaded: $LOCAL_FILE to $REMOTE_HOST:$REMOTE_FILE"
else
echo "FTP transfer failed."
exit 1
fi
# Clean up local file (optional)
# rm "$LOCAL_FILE"
# echo "Cleaned up local file: $LOCAL_FILE"
The ftp -inv command is key here. -i disables interactive prompting (like asking "Are you sure you want to overwrite?"), and -n prevents auto-login. The <<EOF ... EOF is a "here document," which feeds the commands between the EOF markers directly into the ftp command’s standard input.
Inside the here document:
user $FTP_USER $FTP_PASS: Authenticates with the FTP server. For anonymous FTP, a valid email address is typically required for the password.binary: Sets the transfer mode to binary. This is crucial for non-text files and generally safer for all file types to avoid unexpected line ending conversions.prompt off: Explicitly turns off prompting, even though-iis already used. It’s good practice to be redundant here.cd "$REMOTE_DIR": Changes the directory on the remote server to where you want to upload the file.put "$LOCAL_FILE" "$FILENAME": Uploads the local file to the remote server. The first argument is the local path, and the second is the desired remote filename.quit: Closes the FTP connection.
The script first creates a sample local file, then checks its existence. After the ftp command, it checks the exit status ($?). A status of 0 indicates success.
A common pitfall is forgetting to set the transfer mode to binary. If you’re transferring anything other than plain ASCII text, using the default ASCII mode can corrupt your files by altering line endings or character encodings.
If you need to download files, you’d use the get command instead of put, and specify the remote file first, then the local destination.
The next hurdle is handling more complex scenarios like resuming interrupted transfers or dealing with servers that require specific TLS/SSL configurations, which the basic ftp client in Bash doesn’t easily support.