IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Linux下自动备份系统脚本指南

    chancel发表于 2024-07-22 00:00:00
    love 0
    <![CDATA[

    服务器上的备份脚本是好几年前写的,前段时间发现有一些小问题,正好趁这个机会重写一下顺便回顾以下Bash语法

    以下内容是从头搜集整理的Bash语法基础,若有错误欢迎指出

    1. shell

    shell是一种统称符合其语法规则语言的简称

    shell是一个命令行解释器,为类Unix操作系统提供一个命令行用户界面

    命令行用户界面也称之为Command Line Interface(CLI)

    在计算机领域,shell通常代指Bash是因为Bash在原始的shell(burne again shell,即SH)程序上增强了许多功能,提供了现代操作系统的非常多基础设施如环境变量、进程管理等

    所以通常说shell时都会代指Bash,除了Bash外,现在也有许多其他shell如Cshell、Kshell等

    Linux发行版都支持sh以及bash环境,无需安装,下面是Bash语法入门

    2. 语法

    Bash的语法简单,但毕竟是一门较老的语言了,在许多特点上是比较反直觉的,下面直接将一些语法点整理出来,以供参考

    首先,Bash的脚本一般有开头标记来告诉环境需要什么脚本解释器,linux下script大部分情况下都是由Bash解释器来执行的

    编辑一个hello.sh文件,内容如下:

    Bash
    #!/bin/Bash
    echo "Hello World! "
    

    赋予权限,并执行,你就可以得到一个输出:"Hello World"

    Bash
    chmod +x hello.sh
    # 执行方法1. 使用指定解释器执行
    /bin/Bash hello.sh
    # 执行方法2. 因为文件开头已经写了执行器类型,直接调用(./指当前目录,如有不理解请自行搜索)
    ./hello.sh
    

    2.1. 变量

    编辑hello.sh文件,内如如下:

    Bash
    #!/bin/Bash
    
    # 变量声明
    var_hello_str='Hello World!'
    # 使用1. 不带花括号
    echo $pick_hero 
    # 使用2. 带花括号(推荐写法)
    echo ${pick_hero}
    

    变量命名规则如下:

    • 只能使用英文字母,数字和下划线且首字符不能以数字开头
    • 中间不能有空格,不能使用标点符号
    • 不能使用保留关键字

    Bash保留关键字如下

    类型 关键字
    判断 if、then、else、elif、fi
    循环 for、do、done、while、until、break、continue、in
    选择 case、esac
    函数 function、return、exit
    其他 select、time、{}、[[]]、(())、!

    保留字相对比较多,更具体可以参考Bash手册

    • https://www.gnu.org/software/bash/manual/bash.html

    声明变量参考如下:

    Bash
    #!/bin/Bash
    
    # 定义并设置只读变量,只读变量不能被重新定义或删除
    readonly my_name="chancel"
    
    # 拼接字符串
    str01="hello"
    str02="world"
    echo "${str01} ${str02}" # 用空格拼接两个字符串
    
    # 定义数组
    myArray=("x" "y" "z")
    echo "${myArray[0]}" #取出第一个元素
    echo "${myArray[*]}" # 取出所有元素
    echo "${myArray[@]}" # 取出所有元素
    
    # 遍历数组
    for var in "${myArray[@]}"; do
        echo "$var"
    done
    
    # 遍历数组并打印索引和元素
    for i in "${!myArray[@]}"; do
        printf "%s\t%s\n" "$i" "${myArray[$i]}"
    done
    
    # 使用while循环遍历数组
    i=0
    while [ $i -lt ${#myArray[@]} ]; do
        echo "${myArray[$i]}"
        ((i++))
    done
    

    2.2. 参数

    在写脚本时传递参数是很常见的做法:

    Bash
    ./demo.sh -name chancel
    

    接收参数并声明为变量:

    Bash
    #!/bin/Bash -e
    show_help() {
        echo "$0 [-h|-?|--help] [--who me] [--why hhh]"
        echo "-h|-?|--help    显示帮助"
        echo "--who           输入你是谁"
    }
    
    while [[ $# -gt 0 ]]; do
        case $1 in
        -h | -\? | --help)
            show_help
            exit 0
            ;;
        --who)
            WHO="${2}"
            shift
            ;;
        *)
            echo -e "Error: $0 invalid option '$1'\nTry '$0 --help' for more information.\n" >&2
            exit -1
            ;;
        esac
        shift
    done
    

    使用效果

    Bash
    $ ./demo.sh -h
    ./demo.sh [-h|-?|--help] [--who me] [--why hhh]
    -h|-?|--help    显示帮助
    --who           输入你是谁
    

    2.3. if else

    控制流程方法如下:

    Bash
    # if写法
    if condition
    then
        command1 
        command2
        ...
        commandN 
    fi
    
    # if-else写法
    if condition1
    then
        command1
    elif condition2 
    then 
        command2
    else
        commandN
    fi
    

    参考示例:

    Bash
    #!/bin/Bash -e
    x=100
    y=200
    if [ $x == $y]
    then
        echo "x = y"
    elif [ $x -gt $y ]
    then
        echo "x > y"
    else
        echo "x < y"
    

    2.4. 运算符

    Bash的运算符比较简单,拢共如下几个

    参数 说明
    -eq =
    -ne !=
    -gt >
    -ge >=
    -lt =<
    -le <=
    -z(字符串) 字符串长度为零
    -n(字符串) 字符串长度不为零

    运算符例子如下:

    Bash
    #!/bin/Bash
    
    # 加减乘除运算
    x=100
    y=200
    $z=$[x+y] #这语法有点奇怪,且实测等号两侧不可空格(写惯了c#可能很不习惯这种写法)
    echo $z
    
    # 字符串判断
    x="hello"
    y="hallo"
    if test $x = $y
    then
        echo "字符串内容相同"
    else
        echo "字符串内容不同"
    fi
    

    2.5. 其他常见语法

    除以上语法外,常见的语法还包括:

    • printf
    • function
    • 输入输出重定向
    • 脚本引入
    • 关于文件的运算符

    例子如下:

    Bash
    #!/bin/bash
    
    # 定义一个函数
    greet() {
        printf "Hello, %s!\n" "$1"
    }
    
    # 输入输出重定向
    ls > files.txt
    
    # 调用函数并传递参数
    greet "John"
    
    # 判断文件是否存在
    if [ -f "files.txt" ]; then
        printf "文件files.txt存在\n"
    else
        printf "文件files.txt不存在\n"
    fi
    
    # 引入其他脚本文件
    source helper.sh
    
    # 调用引入的函数并传递参数
    greet "Alice"
    

    3. 备份脚本

    我的需求主要有以下2点

    • 备份MySQL中的所有数据库
    • 备份/opt目录下的所有程序

    基于以上语法,可实现脚本如下:

    Bash
    #!/bin/bash
    # author: chancel
    # url: www.chancel.me
    
    show_help() {
        echo "$0 [-h|-?|--help] [--temp /tmp/_backup] [--target /opt/backup/] [--dbuser root] [--dbpasswd passwd] [--extra /opt]"
        echo "-h|-?|--help    显示帮助"
        echo "--temp          设置备份文件时的缓存目录"
        echo "--target        设置备份文件的目标(存放)路径"
        echo "--dbuser        设置mysql数据库用户名称"
        echo "--dbpasswd      设置mysql数据库用户密码"
        echo "--extra         额外需要备份的目录,以空格分开不同目录"
    }
    
    create_folders() {
        echo "创建必要的文件夹"
        mkdir -p "$mysql_backup_dir"
    }
    
    backup_mysql_databases() {
        echo "备份mysql数据库"
        databases=$(mysql -u"$dbuser" -p"$dbpasswd" -e "SHOW DATABASES;" | tr -d "| " | grep -v Database)
        for db in $databases; do
            if [[ "$db" != "sentry" ]] && [[ "$db" != "information_schema" ]] && [[ "$db" != "performance_schema" ]] && [[ "$db" != "mysql" ]] && [[ "$db" != _* ]]; then
                echo "正在导出数据库$db"
                mysqldump -u"$dbuser" -p"$dbpasswd" --databases "$db" > "$mysql_backup_dir/$(date +%Y%m%d)-$db.sql"
            fi
        done
    }
    
    delete_previous_backup() {
        echo "正在删除上一次产生的备份包"
        rm -f "$old_backup_file_path"
    }
    
    create_backup_file() {
        echo "创建备份文件 $new_backup_file_path"
        tar -zcvf "$new_backup_file_path" "$mysql_backup_dir" $extra
        mv "$new_backup_file_path" "$target"
    }
    
    delete_temp_folder() {
        echo "删除临时文件夹 $temp"
        rm -rf "$temp"
        echo "备份结束"
    }
    
    # 解析命令行参数
    while [[ $# -gt 0 ]]; do
        case $1 in
        -h | -\? | --help)
            show_help
            exit 0
            ;;
        --temp)
            temp="$2"
            shift
            ;;
        --target)
            target="$2"
            shift
            ;;
        --dbuser)
            dbuser="$2"
            shift
            ;;
        --dbpasswd)
            dbpasswd="$2"
            shift
            ;;
        --extra)
            extra="$2"
            shift
            ;;
        --)
            shift
            break
            ;;
        *)
            echo -e "错误: $0 无效操作 '$1'\n可输入命令 '$0 --help' 获取更多帮助.\n" >&2
            exit -1
            ;;
        esac
        shift
    done
    
    # 设置变量
    mysql_backup_dir="$temp/mysql_backup"
    new_backup_file_path="$temp/$(date +%Y%m%d).tar.gz"
    old_backup_file_path="$target/$(date -d -1day +%Y%m%d).tar.gz"
    
    # 执行备份操作
    create_folders
    backup_mysql_databases
    delete_previous_backup
    create_backup_file
    delete_temp_folder
    

    4. 尾语

    参考这份文档,根据需要可自定修改,你就可以快速得到一份备份脚本



沪ICP备19023445号-2号
友情链接