v1.0
This commit is contained in:
commit
5ecba558fd
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
backup.conf
|
11
backup.conf.example
Normal file
11
backup.conf.example
Normal file
@ -0,0 +1,11 @@
|
||||
# WebDav 服务器
|
||||
server="https://localhost"
|
||||
|
||||
# 用户
|
||||
user=""
|
||||
|
||||
# 密码
|
||||
pass=""
|
||||
|
||||
# 忽略 SSL 证书校验
|
||||
ignore_cert=false
|
339
webdav_backup.sh
Executable file
339
webdav_backup.sh
Executable file
@ -0,0 +1,339 @@
|
||||
#!/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 "-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"
|
||||
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" -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" -f --header 'Depth: 1' $curl_extra_args)
|
||||
echo $flist_html | grep -Po '<D:href>.+?\/\K(.+?)(?=<\/D:href>)' -o | grep $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() {
|
||||
[[ $_try_return -eq 0 ]] && eval $({ ! _1=$({ _0=$($@); } 2>&1; echo -n "_try_out='$_0' _try_return=$? " >&2); echo -n "_try_err='$_1'"; } 2>&1)
|
||||
}
|
||||
|
||||
__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:u:p:k:I
|
||||
LONGOPTS=config,verbose,help,version,prefix:,server:,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
|
||||
;;
|
||||
-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
|
Loading…
x
Reference in New Issue
Block a user