更新 z.ai/shell/ftp_backup.sh

1、支持apline 等小众的系统,尤其是兼容RHEL系的其它新系统
2、为了方便调用但是又保证安全,我回头会直接在ftp服务器信息配置的位置手工把IP 端口和用户名填写进去,但是密码需要我在调用的时候输入,密码会又特殊符号。
./ftp_backup.sh -p密码 目录1 目录2 目录3
This commit is contained in:
2025-10-24 20:45:04 +00:00
parent 10bcfd814a
commit bccfaeccfd
2 changed files with 175 additions and 156 deletions
-156
View File
@@ -1,156 +0,0 @@
#!/bin/bash
# ==============================================================================
# 脚本名称: ftp_backup.sh
# 功能描述: 将指定的一个或多个目录打包压缩后,自动上传到FTP服务器。
# 调用方式: ./ftp_backup.sh 目录1 [目录2] [目录3] ...
# 作者: AI Assistant
# 版本: 1.1
# ==============================================================================
# --- 配置区 (请在此处修改您的FTP服务器信息) ---
# FTP服务器信息
FTP_HOST="your_ftp_server_ip" # FTP服务器IP地址或域名
FTP_PORT="21" # FTP服务器端口 (默认为21)
FTP_USER="your_username" # FTP登录用户名
FTP_PASS="your_password" # FTP登录密码
# 上传到FTP服务器的哪个目录 (如果不存在,请确保FTP账户有创建权限,或手动创建)
FTP_REMOTE_DIR="/backup"
# 本地临时目录,用于存放生成的压缩包 (通常使用/tmp)
TEMP_BACKUP_DIR="/tmp"
# --- 配置区结束 ---
# --- 脚本主逻辑 (通常无需修改以下内容) ---
# 开启严格模式:遇到错误立即退出,使用未定义变量时报错,管道中任一命令失败则整个管道失败
set -euo pipefail
# 定义一个清理函数,用于在脚本退出时删除临时文件
cleanup() {
if [[ -n "${ARCHIVE_NAME:-}" && -f "${TEMP_BACKUP_DIR}/${ARCHIVE_NAME}" ]]; then
echo "清理临时文件: ${TEMP_BACKUP_DIR}/${ARCHIVE_NAME}"
rm -f "${TEMP_BACKUP_DIR}/${ARCHIVE_NAME}"
fi
}
# 无论脚本如何退出(成功、失败、被中断),都会执行cleanup函数
trap cleanup EXIT
# 显示使用方法
usage() {
echo "用法: $0 目录1 [目录2] [目录3] ..."
echo "示例: $0 /var/www/html /etc/nginx /home/user/documents"
exit 1
}
# 检查并安装ftp客户端
check_dependencies() {
echo "正在检查 ftp 客户端是否已安装..."
if ! command -v ftp &> /dev/null; then
echo "ftp 客户端未找到,正在尝试自动安装..."
# 检测操作系统类型
if [[ -f /etc/debian_version ]]; then
# Debian/Ubuntu 系统
echo "检测到 Debian/Ubuntu 系统,使用 apt-get 安装..."
sudo apt-get update
sudo apt-get install -y ftp
elif [[ -f /etc/redhat-release ]]; then
# CentOS/RHEL/Fedora 系统
echo "检测到 RedHat/CentOS 系统,使用 yum 安装..."
sudo yum install -y ftp
else
echo "错误: 无法识别您的Linux发行版,请手动安装 ftp 客户端。"
exit 1
fi
# 再次检查是否安装成功
if ! command -v ftp &> /dev/null; then
echo "错误: ftp 客户端安装失败!"
exit 1
fi
echo "ftp 客户端安装成功。"
else
echo "ftp 客户端已安装。"
fi
}
# 创建压缩包
create_archive() {
local dirs_to_backup=("$@")
# 生成唯一的压缩包名:主机名_时间戳.tar.gz
ARCHIVE_NAME="backup_$(hostname)_$(date +%Y%m%d_%H%M%S).tar.gz"
local full_archive_path="${TEMP_BACKUP_DIR}/${ARCHIVE_NAME}"
echo "正在创建压缩包: ${full_archive_path}"
echo "包含的目录: ${dirs_to_backup[*]}"
# 使用 tar 命令创建 .tar.gz 压缩包
# -c: 创建, -z: gzip压缩, -f: 指定文件名, -p: 保留权限
tar -czpf "${full_archive_path}" "${dirs_to_backup[@]}"
echo "压缩包创建成功!"
}
# 上传到FTP服务器
upload_to_ftp() {
local local_file="${TEMP_BACKUP_DIR}/${1}"
echo "正在上传 ${local_file} 到 FTP 服务器 ${FTP_HOST}:${FTP_PORT}${FTP_REMOTE_DIR}"
# 使用 ftp 的 -inv 选项进行非交互式上传
# -i: 关闭交互式提示
# -n: 禁止自动登录
# -v: 显示详细输出
ftp -inv << EOF
open ${FTP_HOST} ${FTP_PORT}
user ${FTP_USER} ${FTP_PASS}
binary
mkdir ${FTP_REMOTE_DIR}
cd ${FTP_REMOTE_DIR}
put ${local_file} ${1}
bye
EOF
echo "文件上传成功!"
}
# ==============================================================================
# 主程序入口
# ==============================================================================
# 1. 检查是否提供了目录参数
if [ "$#" -eq 0 ]; then
usage
fi
# 2. 验证所有提供的目录是否存在
echo "正在验证输入的目录..."
for dir in "$@"; do
if [ ! -d "$dir" ]; then
echo "错误: 目录 '$dir' 不存在!"
exit 1
fi
done
echo "所有目录验证通过。"
# 3. 检查并安装依赖
check_dependencies
# 4. 创建压缩包
create_archive "$@"
# 5. 上传压缩包
upload_to_ftp "${ARCHIVE_NAME}"
# 6. 脚本执行完毕
echo "========================================="
echo "备份任务全部完成!"
echo "备份文件: ${ARCHIVE_NAME}"
echo "========================================="
exit 0
+175
View File
@@ -0,0 +1,175 @@
#!/bin/bash
# ==============================================================================
# 脚本名称: ftp_backup.sh
# 功能描述: 将指定的一个或多个目录通过数据流打包并直接上传到FTP服务器。
# 无需生成临时文件,高效且节省磁盘空间。
# 调用方式:
# 1. 交互式输入密码 (推荐, 更安全):
# ./ftp_backup.sh 目录1 [目录2] ...
# 2. 通过 -p 参数指定密码 (不推荐, 有安全风险):
# ./ftp_backup.sh -p '你的密码' 目录1 [目录2] ...
# 作者: AI Assistant
# 版本: 2.0
# ==============================================================================
# --- 配置区 (请在此处修改您的FTP服务器信息) ---
# FTP服务器信息
FTP_HOST="your_ftp_server_ip" # FTP服务器IP地址或域名
FTP_PORT="21" # FTP服务器端口 (默认为21)
FTP_USER="your_username" # FTP登录用户名
# 密码将在运行时通过交互式输入或 -p 参数提供
# 上传到FTP服务器的哪个目录 (如果不存在,请确保FTP账户有创建权限)
FTP_REMOTE_DIR="/backup"
# --- 配置区结束 ---
# --- 脚本主逻辑 (通常无需修改以下内容) ---
# 开启严格模式
set -euo pipefail
# 用于存储密码的变量
FTP_PASS=""
# 显示使用方法
usage() {
echo "用法:"
echo " $0 目录1 [目录2] ... # 交互式输入密码 (推荐)"
echo " $0 -p '密码' 目录1 [目录2] ... # 通过参数提供密码 (不安全)"
echo ""
echo "示例:"
echo " $0 /var/www/html /etc/nginx"
echo " $0 -p 'MyP@ssw0rd!' /home/user"
exit 1
}
# 检查并安装依赖包 (兼容 Alpine, Debian/Ubuntu, RHEL/CentOS/Fedora)
install_package_if_missing() {
local package_name="$1"
if ! command -v "${package_name}" &> /dev/null; then
echo "依赖 '${package_name}' 未找到,正在尝试自动安装..."
# 检测包管理器并安装
if command -v apk &> /dev/null; then
echo "检测到 Alpine 系统,使用 apk 安装..."
sudo apk add "${package_name}"
elif command -v apt-get &> /dev/null; then
echo "检测到 Debian/Ubuntu 系统,使用 apt-get 安装..."
sudo apt-get update && sudo apt-get install -y "${package_name}"
elif command -v dnf &> /dev/null; then
echo "检测到使用 dnf 的系统 (如 Fedora/RHEL 8+),使用 dnf 安装..."
sudo dnf install -y "${package_name}"
elif command -v yum &> /dev/null; then
echo "检测到使用 yum 的系统 (如 CentOS 7),使用 yum 安装..."
sudo yum install -y "${package_name}"
else
echo "错误: 无法识别您的包管理器,请手动安装 '${package_name}'。"
exit 1
fi
# 再次检查
if ! command -v "${package_name}" &> /dev/null; then
echo "错误: '${package_name}' 安装失败!"
exit 1
fi
echo "'${package_name}' 安装成功。"
else
echo "依赖 '${package_name}' 已满足。"
fi
}
# 流式打包并上传
stream_and_upload() {
local dirs_to_backup=("$@")
# 生成唯一的压缩包名
local archive_name="backup_$(hostname)_$(date +%Y%m%d_%H%M%S).tar.gz"
local ftp_url="ftp://${FTP_HOST}:${FTP_PORT}${FTP_REMOTE_DIR}/${archive_name}"
echo "========================================="
echo "准备开始流式备份和上传..."
echo "目标FTP: ${FTP_HOST}:${FTP_PORT}"
echo "远程目录: ${FTP_REMOTE_DIR}"
echo "备份内容: ${dirs_to_backup[*]}"
echo "远程文件名: ${archive_name}"
echo "========================================="
# 使用 tar 和 curl 管道进行流式处理
# tar -czf - : - 表示输出到标准输出
# curl -T - : -T - 表示从标准输入读取文件内容上传
# -u : 提供用户名和密码
# --ftp-create-dirs : 自动创建远程目录 (如果需要)
# --ftp-pasv : 使用被动模式 (更兼容防火墙)
# 我们使用 PIPESTATUS 来检查管道中任何一个命令是否失败
tar -czpf - "${dirs_to_backup[@]}" | curl -T - -u "${FTP_USER}:${FTP_PASS}" --ftp-create-dirs --ftp-pasv "${ftp_url}"
# 检查管道命令的退出状态
if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]]; then
echo "错误: 打包或上传过程中失败!"
echo "tar 退出码: ${PIPESTATUS[0]}, curl 退出码: ${PIPESTATUS[1]}"
exit 1
fi
echo "========================================="
echo "备份任务全部完成!"
echo "文件已成功上传为: ${archive_name}"
echo "========================================="
}
# ==============================================================================
# 主程序入口
# ==============================================================================
# 1. 解析命令行参数
while getopts ":p:" opt; do
case ${opt} in
p )
FTP_PASS="${OPTARG}"
;;
\? )
echo "无效的选项: -$OPTARG" 1>&2
usage
;;
: )
echo "选项 -$OPTARG 需要一个参数." 1>&2
usage
;;
esac
done
shift $((OPTIND -1))
# 2. 检查是否提供了目录参数
if [ "$#" -eq 0 ]; then
usage
fi
# 3. 如果没有通过 -p 提供密码,则交互式输入
if [[ -z "${FTP_PASS}" ]]; then
echo "请输入FTP密码:"
# -s: 静默输入,不回显到屏幕
# -r: 允许输入反斜杠,防止特殊字符被转义
read -sr FTP_PASS
echo "" # 换行
fi
# 4. 验证所有提供的目录是否存在
echo "正在验证输入的目录..."
for dir in "$@"; do
if [ ! -d "$dir" ]; then
echo "错误: 目录 '$dir' 不存在!"
exit 1
fi
done
echo "所有目录验证通过。"
# 5. 检查并安装依赖 (curl 和 tar)
install_package_if_missing "curl"
install_package_if_missing "tar"
# 6. 执行流式打包和上传
stream_and_upload "$@"
exit 0