348 lines
7.4 KiB
Bash
Executable File
348 lines
7.4 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
SCRIPT_DESC="WebDav 备份脚本"
|
||
SCRIPT_VERSION=1.0
|
||
SCRIPT_AUTHOR=KAAAsS
|
||
|
||
show_help() {
|
||
__opt() { printf " %-30s%s\n" "$1" "$2"; }
|
||
echo "用法:"
|
||
echo " $0 待备份文件路径"
|
||
echo " $0 [选项] [--] 待备份文件路径"
|
||
echo
|
||
echo $SCRIPT_DESC
|
||
echo
|
||
echo "选项:"
|
||
__opt "-x, --prefix <name>" "备份文件前缀"
|
||
__opt "-s, --server <url>" "WebDav 服务器地址,以 \"/\" 结束"
|
||
__opt "-P, --server-path <path>" "WebDav 备份路径,以 \"/\" 结束"
|
||
__opt "-u, --user <user>" "WebDav 用户名"
|
||
__opt "-p, --pass <password>" "WebDav 密码"
|
||
__opt "-k, --keeps n" "保留最近几个备份文件。默认为0,不删除备份文件"
|
||
__opt "-I, --ignore-cert" "忽略 WebDav 证书"
|
||
echo
|
||
__opt "-c, --config" "配置文件"
|
||
__opt "-v, --verbose" "打印调试信息"
|
||
__opt "-h, --help" "显示此帮助"
|
||
__opt "-V, --version" "显示版本"
|
||
echo
|
||
}
|
||
|
||
#----------#
|
||
# 可配置变量 #
|
||
#----------#
|
||
|
||
verbose=false
|
||
tmpfs="/tmp"
|
||
prefix="backup"
|
||
server="http://your-site/dav"
|
||
server_path=
|
||
user="guest"
|
||
pass=""
|
||
backup_path=-
|
||
keeps=0
|
||
retry=3
|
||
ignore_cert=false
|
||
curl_extra_args=
|
||
|
||
#--------
|
||
# 脚本逻辑
|
||
#--------
|
||
|
||
filename=-
|
||
backup_dir=-
|
||
|
||
exit_handler() {
|
||
local error_code="$?"
|
||
# test $error_code == 0 && return;
|
||
__dbg "清理临时文件..."
|
||
if [[ -f $filename ]]; then
|
||
__dbg " $filename"
|
||
rm -rf $filename
|
||
fi
|
||
if [[ -d $backup_dir ]]; then
|
||
__dbg " $backup_dir"
|
||
rm -rf $backup_dir
|
||
fi
|
||
exit "$error_code"
|
||
}
|
||
|
||
make_backup() {
|
||
if [ ! -d $backup_path ]; then
|
||
__err "待备份路径不存在!"
|
||
exit 2
|
||
fi
|
||
|
||
filename="$tmpfs/$prefix"_"$(date +%y%m%d_%H%M%S).tar.gz"
|
||
backup_dir=$tmpfs/${prefix}_$(date +%H%M%S)
|
||
|
||
if [ -d $backup_dir ]; then
|
||
rm -rf $backup_dir
|
||
fi
|
||
|
||
__dbg "备份文件路径 $backup_path 至 $backup_dir"
|
||
|
||
echo -n "打包备份路径... "
|
||
mkdir $backup_dir
|
||
__try cp -r $backup_path $backup_dir
|
||
__try tar -czvf $filename -C $backup_dir .
|
||
|
||
if __catch e; then
|
||
__color $RED '错误\n'
|
||
__err "打包失败: $e"
|
||
exit 2
|
||
fi
|
||
|
||
__color $GREEN '成功\n'
|
||
__dbg "成功打包至: $filename"
|
||
}
|
||
|
||
upload() {
|
||
for retry_count in $( seq 0 $retry ); do
|
||
|
||
if [[ $retry_count -eq 0 ]]; then
|
||
echo -n "上传备份文件... "
|
||
else
|
||
echo -n "上传备份文件: 第 $retry_count 次重试... "
|
||
fi
|
||
|
||
__try curl -sS --user "$user:$pass" -T $1 "$server$server_path" -f $curl_extra_args
|
||
|
||
if __catch e; then
|
||
__color $RED '错误\n'
|
||
__err "上传失败: $e"
|
||
continue
|
||
fi
|
||
|
||
__color $GREEN '成功\n'
|
||
return 0
|
||
done
|
||
|
||
__err "超过失败重试次数"
|
||
exit 3
|
||
}
|
||
|
||
get_file_list() {
|
||
flist_html=$(curl -sS --user "$user:$pass" -X PROPFIND "$server$server_path" -f --header 'Depth: 1' $curl_extra_args)
|
||
echo $flist_html | grep -Po '<D:href>.+?\/\K(.+?)(?=<\/D:href>)' -o | grep $server_path$prefix | sort
|
||
}
|
||
|
||
delete_file() {
|
||
local file=$1
|
||
|
||
for retry_count in $( seq 0 $retry ); do
|
||
|
||
if [[ $retry_count -eq 0 ]]; then
|
||
echo -n "删除备份 $file... "
|
||
else
|
||
echo -n "删除备份 $file: 第 $retry_count 次重试... "
|
||
fi
|
||
|
||
__try curl -sS --user "$user:$pass" -X DELETE "$server$file" -f $curl_extra_args
|
||
|
||
if __catch e; then
|
||
__color $RED '错误\n'
|
||
__err "删除失败: $e"
|
||
continue
|
||
fi
|
||
|
||
__color $GREEN '成功\n'
|
||
return 0
|
||
done
|
||
|
||
__err "超过失败重试次数"
|
||
exit 3
|
||
}
|
||
|
||
remove_old_backup() {
|
||
echo -n "检查已有备份... "
|
||
__try get_file_list
|
||
|
||
if __catch e; then
|
||
__err "无法取得服务器文件信息: $e"
|
||
__err "删除旧备份失败!"
|
||
__color $RED '错误\n'
|
||
exit 4
|
||
fi
|
||
|
||
__get_output file_list
|
||
|
||
local bk_count=$(echo $file_list | wc -w)
|
||
|
||
if [[ $bk_count -gt $keeps ]];then
|
||
local del_count=`expr $bk_count - $keeps`
|
||
|
||
__color $BLUE "$del_count 个过时备份\n"
|
||
__dbg "现存文件列表:$file_list"
|
||
|
||
# 删除文件
|
||
local del_lst=$(echo $file_list | cut -d " " -f 1-$del_count)
|
||
for file in $del_lst; do
|
||
delete_file $file
|
||
done
|
||
else
|
||
__color $GREEN '无需删除\n'
|
||
__dbg "现存文件列表:$file_list"
|
||
fi
|
||
}
|
||
|
||
main() {
|
||
trap exit_handler EXIT
|
||
make_backup
|
||
upload $filename
|
||
if [[ $keeps -gt 0 ]]; then
|
||
remove_old_backup
|
||
fi
|
||
}
|
||
|
||
#-------
|
||
# Utils
|
||
#-------
|
||
|
||
__init_util() {
|
||
# DO NOT CALL ME OTHER THEN STARTUP
|
||
_try_return=0
|
||
_try_err=-
|
||
_try_out=-
|
||
}
|
||
|
||
GREEN='0;32' RED='0;31' BLUE='0;34'
|
||
|
||
__color() {
|
||
c=$1
|
||
shift 1
|
||
printf "\033[${c}m$@\033[0m"
|
||
}
|
||
|
||
__dbg() {
|
||
if [ $verbose = true ]; then
|
||
__color $BLUE "$@"
|
||
echo
|
||
fi
|
||
}
|
||
|
||
__err() {
|
||
__color $RED "$0: $@" >&2
|
||
echo
|
||
}
|
||
|
||
__try() {
|
||
if [[ $_try_return -eq 0 ]]; then
|
||
eval $({ ! _1=$({ _0=$($@); } 2>&1; echo -n "_try_out='$_0' _try_return=$? " >&2); echo -n "_try_err='$_1'"; } 2>&1)
|
||
fi
|
||
}
|
||
|
||
__catch() {
|
||
_old_try=$_try_return
|
||
_try_return=0
|
||
export $1="$_try_err"
|
||
[[ $_old_try -ne 0 ]]
|
||
}
|
||
|
||
__get_output() {
|
||
export $1="$_try_out"
|
||
}
|
||
|
||
#--------#
|
||
# 参数解析 #
|
||
#--------#
|
||
|
||
set -o errexit -o pipefail -o noclobber -o nounset
|
||
|
||
! getopt --test > /dev/null
|
||
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
|
||
__err '环境缺少 getopt 以解析参数'
|
||
exit 1
|
||
fi
|
||
|
||
OPTIONS=c:vhVx:s:P:u:p:k:I
|
||
LONGOPTS=config,verbose,help,version,prefix:,server:,server-path:,user:,pass:,keeps:,ignore-cert
|
||
|
||
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
|
||
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
|
||
exit 1
|
||
fi
|
||
eval set -- "$PARSED"
|
||
|
||
while true; do
|
||
case "$1" in
|
||
-c|--config)
|
||
# 解析配置文件
|
||
if [ ! -f "$2" ]; then
|
||
__err "配置文件不存在!"
|
||
exit 1
|
||
fi
|
||
source $2
|
||
shift 2
|
||
;;
|
||
-v|--verbose)
|
||
verbose=true
|
||
shift
|
||
;;
|
||
-h|--help)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
-V|--version)
|
||
echo $SCRIPT_VERSION
|
||
exit 0
|
||
;;
|
||
-x|--prefix)
|
||
prefix="$2"
|
||
shift 2
|
||
;;
|
||
-s|--server)
|
||
server="$2"
|
||
shift 2
|
||
;;
|
||
-P|--server-path)
|
||
server_path="$2"
|
||
shift 2
|
||
;;
|
||
-u|--user)
|
||
user="$2"
|
||
shift 2
|
||
;;
|
||
-p|--pass)
|
||
pass="$2"
|
||
shift 2
|
||
;;
|
||
-k|--keeps)
|
||
keeps="$2"
|
||
shift 2
|
||
;;
|
||
-I|--ignore-cert)
|
||
ignore_cert=true
|
||
shift
|
||
;;
|
||
--)
|
||
# 结束参数解析
|
||
shift
|
||
break
|
||
;;
|
||
*)
|
||
__err "参数解析失败"
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
if [[ $ignore_cert = "true" ]]; then
|
||
curl_extra_args="$curl_extra_args -k"
|
||
fi
|
||
|
||
if [[ $# -gt 1 ]]; then
|
||
__err "仅支持备份一个路径"
|
||
exit 1
|
||
elif [[ $# -eq 1 ]]; then
|
||
backup_path=$1
|
||
fi
|
||
|
||
if [[ $backup_path = - ]]; then
|
||
__err "必须指定备份路径"
|
||
exit 1
|
||
fi
|
||
|
||
__init_util
|
||
main
|