webdav_backup_sh/webdav_backup.sh

348 lines
7.4 KiB
Bash
Raw Normal View History

2022-02-13 19:48:02 +08:00
#!/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>" "备份文件前缀"
2022-02-13 20:01:16 +08:00
__opt "-s, --server <url>" "WebDav 服务器地址,以 \"/\" 结束"
__opt "-P, --server-path <path>" "WebDav 备份路径,以 \"/\" 结束"
2022-02-13 19:48:02 +08:00
__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"
2022-02-13 20:01:16 +08:00
server_path=
2022-02-13 19:48:02 +08:00
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
2022-02-13 20:01:16 +08:00
__try curl -sS --user "$user:$pass" -T $1 "$server$server_path" -f $curl_extra_args
2022-02-13 19:48:02 +08:00
if __catch e; then
__color $RED '错误\n'
__err "上传失败: $e"
continue
fi
__color $GREEN '成功\n'
return 0
done
__err "超过失败重试次数"
exit 3
}
get_file_list() {
2022-02-13 20:01:16 +08:00
flist_html=$(curl -sS --user "$user:$pass" -X PROPFIND "$server$server_path" -f --header 'Depth: 1' $curl_extra_args)
2022-03-11 12:58:10 +08:00
echo $flist_html | grep -Po '<D:href>.+?\/\K(.+?)(?=<\/D:href>)' -o | grep $server_path$prefix | sort
2022-02-13 19:48:02 +08:00
}
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
2022-03-11 12:58:10 +08:00
__try curl -sS --user "$user:$pass" -X DELETE "$server$file" -f $curl_extra_args
2022-02-13 19:48:02 +08:00
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() {
2022-02-13 20:15:52 +08:00
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
2022-02-13 19:48:02 +08:00
}
__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
2022-02-13 20:01:16 +08:00
OPTIONS=c:vhVx:s:P:u:p:k:I
LONGOPTS=config,verbose,help,version,prefix:,server:,server-path:,user:,pass:,keeps:,ignore-cert
2022-02-13 19:48:02 +08:00
! 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
;;
2022-02-13 20:01:16 +08:00
-P|--server-path)
server_path="$2"
shift 2
;;
2022-02-13 19:48:02 +08:00
-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