#!/bin/bash # FTP备份脚本 # 用法: ./ftp_backup.sh -p密码 目录1 目录2 目录3 文件1 set -e # 遇到错误立即退出 # 配置信息(请根据实际情况修改) FTP_SERVER="ftp.example.com" FTP_PORT="21" FTP_USER="username" BACKUP_PREFIX="backup" REMOTE_PATH="/backups" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" } warn() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] 警告: $1${NC}" } error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] 错误: $1${NC}" >&2 exit 1 } # 显示用法信息 usage() { echo "用法: $0 -p密码 目录1 目录2 目录3 文件1" echo "选项:" echo " -p密码 FTP密码(包含特殊字符时请直接跟在-p后面)" echo "示例: $0 -pMy@Complex#Password123 /home/user /etc /var/log /important/file.txt" exit 1 } # 检测系统类型并安装FTP客户端 install_ftp_client() { local ftp_client="" # 检测系统类型 if command -v apt-get >/dev/null 2>&1; then log "检测到 Debian/Ubuntu 系统" ftp_client="ftp" apt-get update && apt-get install -y $ftp_client elif command -v yum >/dev/null 2>&1; then log "检测到 RHEL/CentOS 系统" ftp_client="ftp" yum install -y $ftp_client elif command -v dnf >/dev/null 2>&1; then log "检测到 Fedora/RHEL 8+ 系统" ftp_client="ftp" dnf install -y $ftp_client elif command -v apk >/dev/null 2>&1; then log "检测到 Alpine 系统" ftp_client="lftp" apk add --no-cache $ftp_client elif command -v zypper >/dev/null 2>&1; then log "检测到 openSUSE 系统" ftp_client="ftp" zypper install -y $ftp_client else error "无法检测系统类型或不受支持的系统" fi # 验证安装是否成功 if command -v ftp >/dev/null 2>&1 || command -v lftp >/dev/null 2>&1; then log "FTP客户端安装/验证成功" else error "FTP客户端安装失败" fi } # 检查FTP客户端是否已安装 check_ftp_client() { if command -v ftp >/dev/null 2>&1; then FTP_CMD="ftp" log "找到 ftp 命令" elif command -v lftp >/dev/null 2>&1; then FTP_CMD="lftp" log "找到 lftp 命令" else warn "未找到FTP客户端,尝试安装..." install_ftp_client # 重新检查 if command -v ftp >/dev/null 2>&1; then FTP_CMD="ftp" elif command -v lftp >/dev/null 2>&1; then FTP_CMD="lftp" else error "FTP客户端安装后仍然不可用" fi fi } # 解析命令行参数 parse_arguments() { local password_provided=0 if [ $# -eq 0 ]; then usage fi # 解析-p参数 while getopts "p:" opt; do case $opt in p) FTP_PASS="$OPTARG" password_provided=1 ;; \?) usage ;; esac done shift $((OPTIND -1)) # 检查密码是否提供 if [ $password_provided -eq 0 ]; then error "必须通过 -p参数 提供FTP密码" fi # 检查是否有备份目标 if [ $# -eq 0 ]; then error "必须指定至少一个目录或文件进行备份" fi # 存储要备份的路径 BACKUP_PATHS=("$@") log "密码参数已接收" log "备份目标: ${BACKUP_PATHS[*]}" } # 验证备份路径是否存在 validate_paths() { local invalid_paths=() for path in "${BACKUP_PATHS[@]}"; do if [ ! -e "$path" ]; then warn "路径不存在: $path" invalid_paths+=("$path") fi done if [ ${#invalid_paths[@]} -eq ${#BACKUP_PATHS[@]} ]; then error "所有指定的备份路径都不存在" elif [ ${#invalid_paths[@]} -gt 0 ]; then warn "以下路径将被忽略: ${invalid_paths[*]}" # 移除无效路径 local valid_paths=() for path in "${BACKUP_PATHS[@]}"; do if [ -e "$path" ]; then valid_paths+=("$path") fi done BACKUP_PATHS=("${valid_paths[@]}") fi } # 创建备份文件 create_backup() { local timestamp=$(date +'%Y%m%d_%H%M%S') BACKUP_FILE="${BACKUP_PREFIX}_${timestamp}.tar.gz" log "开始创建备份文件: $BACKUP_FILE" # 创建临时目录 local temp_dir=$(mktemp -d) trap 'rm -rf "$temp_dir"' EXIT # 复制要备份的文件和目录到临时位置,保持相对路径结构 for path in "${BACKUP_PATHS[@]}"; do if [ -e "$path" ]; then local parent_dir=$(dirname "$path") local base_name=$(basename "$path") if [ "$parent_dir" = "/" ]; then # 处理根目录下的文件/目录 cp -r "$path" "$temp_dir/root_$base_name" else # 创建父目录结构并复制 mkdir -p "$temp_dir/$parent_dir" cp -r "$path" "$temp_dir/$parent_dir/" fi fi done # 创建tar.gz压缩包 if tar -czf "$BACKUP_FILE" -C "$temp_dir" . 2>/dev/null; then log "备份文件创建成功: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))" else error "创建备份文件失败" fi } # 使用ftp命令上传 upload_with_ftp() { log "使用ftp上传文件..." # 创建ftp命令脚本 local ftp_script=$(mktemp) cat > "$ftp_script" << EOF open $FTP_SERVER $FTP_PORT user $FTP_USER $FTP_PASS binary mkdir $REMOTE_PATH cd $REMOTE_PATH put $BACKUP_FILE quit EOF if ftp -n < "$ftp_script" > /tmp/ftp_upload.log 2>&1; then log "FTP上传成功" rm -f "$ftp_script" "/tmp/ftp_upload.log" return 0 else error "FTP上传失败,查看 /tmp/ftp_upload.log 获取详细信息" fi } # 使用lftp命令上传(Alpine Linux) upload_with_lftp() { log "使用lftp上传文件..." if lftp -e "set ftp:ssl-allow no; open $FTP_SERVER; user $FTP_USER '$FTP_PASS'; mkdir -p $REMOTE_PATH; cd $REMOTE_PATH; put $BACKUP_FILE; quit" > /tmp/lftp_upload.log 2>&1; then log "LFTP上传成功" rm -f "/tmp/lftp_upload.log" return 0 else error "LFTP上传失败,查看 /tmp/lftp_upload.log 获取详细信息" fi } # 上传备份文件 upload_backup() { log "开始上传备份文件到 $FTP_SERVER:$REMOTE_PATH" case $FTP_CMD in "ftp") upload_with_ftp ;; "lftp") upload_with_lftp ;; *) error "不支持的FTP命令: $FTP_CMD" ;; esac } # 清理临时文件 cleanup() { if [ -f "$BACKUP_FILE" ]; then rm -f "$BACKUP_FILE" log "已清理本地备份文件: $BACKUP_FILE" fi } # 主函数 main() { log "FTP备份脚本开始执行" # 解析参数 parse_arguments "$@" # 验证路径 validate_paths # 检查FTP客户端 check_ftp_client # 创建备份 create_backup # 上传备份 upload_backup # 清理 cleanup log "FTP备份完成!" } # 脚本入口点 main "$@"