自动化文件传输:使用Shell脚本实现SFTP批量上传
1. 为什么需要自动化SFTP上传在日常工作中我们经常需要将本地文件上传到远程服务器。比如网站日志备份、数据库导出文件同步、报表数据上传等场景。如果每次都手动操作不仅效率低下还容易出错。想象一下每天凌晨3点要手动上传几十个日志文件这简直是运维人员的噩梦。我曾在电商公司负责订单数据的同步工作最初每天手动上传CSV文件经常因为操作失误导致数据延迟。后来改用Shell脚本自动化处理不仅解放了双手还实现了零差错传输。这就是自动化脚本的魅力所在。SFTPSSH File Transfer Protocol相比普通FTP更安全它通过SSH加密传输数据。结合Shell脚本我们可以实现定时自动上传批量文件处理错误自动重试操作日志记录2. 基础环境准备2.1 必备工具检查在开始编写脚本前先确认你的Linux/macOS系统已安装以下工具lftp客户端比传统sftp命令更强大ssh客户端基础Shell环境bash/sh检查安装状态的命令which lftp which ssh echo $SHELL如果缺少lftp可以通过包管理器安装# Ubuntu/Debian sudo apt install lftp # CentOS/RHEL sudo yum install lftp # macOS brew install lftp2.2 测试SFTP连接建议先手动测试SFTP连接是否正常lftp -u username,password sftp://server_ip:port连接成功后执行ls查看目录确认有写入权限。注意生产环境中不建议在命令行直接输入密码后续我们会介绍更安全的认证方式3. 编写基础上传脚本3.1 最小化脚本示例创建一个名为sftp_upload.sh的文件内容如下#!/bin/bash # 基本参数检查 if [ $# -lt 3 ]; then echo Usage: $0 local_file remote_dir config_file exit 1 fi LOCAL_FILE$1 REMOTE_DIR$2 CONFIG_FILE$3 # 读取配置文件 source $CONFIG_FILE # 上传核心命令 lftp -u $SFTP_USER,$SFTP_PASS sftp://$SFTP_HOST:$SFTP_PORT EOF set net:timeout 10 set net:max-retries 3 lcd $(dirname $LOCAL_FILE) mkdir -p $REMOTE_DIR cd $REMOTE_DIR put $(basename $LOCAL_FILE) bye EOF # 检查执行结果 if [ $? -eq 0 ]; then echo $(date) - 上传成功: $LOCAL_FILE else echo $(date) - 上传失败: $LOCAL_FILE exit 2 fi配套的配置文件sftp.confSFTP_HOSTyour.server.com SFTP_PORT22 SFTP_USERusername SFTP_PASSpassword3.2 脚本功能解析这个基础版本已经实现了参数校验至少需要3个参数配置文件分离避免密码硬编码自动创建远程目录超时和重试设置执行结果检查使用方法chmod x sftp_upload.sh ./sftp_upload.sh /path/to/file.txt /remote/path sftp.conf4. 高级功能实现4.1 批量文件上传实际场景中我们经常需要上传整个目录的文件。修改脚本支持批量上传#!/bin/bash # ...前面部分保持不变... # 判断是否是目录 if [ -d $LOCAL_FILE ]; then # 上传目录下所有文件 find $LOCAL_FILE -type f | while read file; do lftp -u $SFTP_USER,$SFTP_PASS sftp://$SFTP_HOST:$SFTP_PORT EOF set net:timeout 10 lcd $(dirname $file) mkdir -p $REMOTE_DIR cd $REMOTE_DIR put $(basename $file) bye EOF [ $? -eq 0 ] echo 上传成功: $file || echo 上传失败: $file done else # 单个文件上传逻辑 # ...保持之前的单个文件上传代码... fi4.2 使用SSH密钥认证更安全的方式是使用SSH密钥替代密码认证。操作步骤生成密钥对ssh-keygen -t rsa -b 4096将公钥上传到服务器ssh-copy-id -i ~/.ssh/id_rsa.pub userserver修改脚本使用密钥认证lftp -u $SFTP_USER, sftp://$SFTP_HOST:$SFTP_PORT EOF set sftp:connect-program ssh -a -x -i /path/to/private_key ... EOF4.3 日志记录与报警完善的脚本应该记录详细日志并支持错误报警LOG_FILE/var/log/sftp_upload.log function log { echo $(date %Y-%m-%d %H:%M:%S) - $1 | tee -a $LOG_FILE } # 在关键操作处添加日志 log 开始上传文件: $LOCAL_FILE # 上传失败时发送报警邮件 if [ $? -ne 0 ]; then log 上传失败: $LOCAL_FILE echo SFTP上传失败: $LOCAL_FILE | mail -s 上传报警 adminexample.com exit 1 fi5. 生产环境最佳实践5.1 错误处理机制完善的错误处理应该包括网络中断重试磁盘空间检查文件完整性校验示例增强版错误处理MAX_RETRY3 RETRY_DELAY5 for ((i1; i$MAX_RETRY; i)); do lftp -u $SFTP_USER,$SFTP_PASS sftp://$SFTP_HOST:$SFTP_PORT EOF ... EOF if [ $? -eq 0 ]; then # 上传成功检查文件大小 local_size$(stat -c%s $LOCAL_FILE) remote_size$(lftp -u $SFTP_USER,$SFTP_PASS sftp://$SFTP_HOST:$SFTP_PORT ls -l $REMOTE_DIR/$(basename $LOCAL_FILE) | awk {print $5}) if [ $local_size -eq $remote_size ]; then log 文件校验成功 break else log 文件大小不匹配准备重试... fi fi if [ $i -lt $MAX_RETRY ]; then log 等待${RETRY_DELAY}秒后重试... sleep $RETRY_DELAY else log 达到最大重试次数上传失败 exit 1 fi done5.2 性能优化技巧处理大量文件时可以考虑并行上传使用xargs或GNU parallel压缩后上传特别适合文本文件增量同步只上传修改过的文件并行上传示例find /local/dir -type f | parallel -j 4 ./sftp_upload.sh {} /remote/dir sftp.conf5.3 定时任务配置使用crontab设置定时上传# 每天凌晨3点同步日志 0 3 * * * /path/to/sftp_upload.sh /var/log /backup/logs sftp.conf /var/log/upload.log 21查看cron日志确认执行情况tail -f /var/log/cron6. 常见问题排查6.1 连接超时问题如果遇到连接超时可以尝试增加超时时间set net:timeout 30检查防火墙设置验证网络连通性telnet $SFTP_HOST $SFTP_PORT6.2 权限被拒绝典型错误及解决方案Permission denied检查远程目录写入权限No such file or directory确保本地文件存在Host key verification failed更新known_hosts文件6.3 文件编码问题处理Windows/Linux换行符差异# 转换文件格式 dos2unix your_script.sh # 检查文件格式 file your_script.sh7. 完整脚本示例结合所有优化点这是一个生产环境可用的完整脚本#!/bin/bash # 配置区域 CONFIG_FILE/etc/sftp_upload.conf LOG_FILE/var/log/sftp_upload.log MAX_RETRY3 RETRY_DELAY10 # 加载配置 source $CONFIG_FILE || { echo 无法加载配置文件; exit 1; } # 日志函数 function log { echo $(date %Y-%m-%d %H:%M:%S) - $1 | tee -a $LOG_FILE } # 参数检查 if [ $# -lt 2 ]; then log 用法: $0 本地文件/目录 远程目录 exit 1 fi LOCAL_PATH$1 REMOTE_DIR$2 # 上传单个文件 function upload_file { local file$1 local retry0 while [ $retry -lt $MAX_RETRY ]; do log 开始上传: $file (尝试 $((retry1))/$MAX_RETRY) lftp -u $SFTP_USER, sftp://$SFTP_HOST:$SFTP_PORT EOF set sftp:connect-program ssh -a -x -i $SSH_KEY set net:timeout 30 set net:max-retries 2 lcd $(dirname $file) mkdir -p $REMOTE_DIR cd $REMOTE_DIR put $(basename $file) bye EOF if [ $? -eq 0 ]; then local local_size$(stat -c%s $file) local remote_size$(lftp -u $SFTP_USER, sftp://$SFTP_HOST:$SFTP_PORT ls -l $REMOTE_DIR/$(basename $file) | awk {print $5}) if [ $local_size -eq $remote_size ]; then log 上传成功: $file return 0 else log 文件大小不匹配: 本地${local_size}字节, 远程${remote_size}字节 fi fi ((retry)) if [ $retry -lt $MAX_RETRY ]; then log 等待${RETRY_DELAY}秒后重试... sleep $RETRY_DELAY fi done log 上传失败: $file return 1 } # 主程序 if [ -f $LOCAL_PATH ]; then # 单个文件上传 upload_file $LOCAL_PATH elif [ -d $LOCAL_PATH ]; then # 目录上传 find $LOCAL_PATH -type f | while read file; do upload_file $file || exit 1 done else log 无效的本地路径: $LOCAL_PATH exit 1 fi log 所有文件处理完成这个脚本包含了我们讨论的所有最佳实践配置文件分离SSH密钥认证完善的日志记录错误重试机制文件校验功能批量上传支持