最近有在部署与管理产品集群,涉及到集群中同步文件、配置项步骤重复,等场景,使用shell脚本来提高效率,同时也是对开发shell脚本的复习

rsync.sh脚本
#!/usr/bin/env bash
# auth 晴风 2024-05-30

# 默认主机IP列表
default_ips=("10.0.0.176" "10.0.0.177")

#
Green="\033[32m"
Font="\033[0m"
Red="\033[31m"
#
purpose="$1"
content="$2"
ips="$3"

function sync_file {
    echo -e "${Green}Synchronize files.${Font}"
    # 使用readlink命令将相对路径转换为绝对路径
    local absolute_path=$(readlink -f "$content")
    # 判断文件夹或文件存在
    if [ -d "$absolute_path" ]; then
        # 遍历主机IP列表
        for ip in "${host_ips[@]}"
        do
            echo -e "${Green}Connecting to host:${Font} $ip"
            # 创建父目录
            ssh -T "$ip" "mkdir -p $(dirname "$absolute_path")"
            # rsync传输文件夹
            rsync -avz -e ssh "$absolute_path" "$ip:$(dirname "$absolute_path")"
        done
    elif [ -f "$absolute_path" ]; then
        # 遍历主机IP列表
        for ip in "${host_ips[@]}"
        do
            echo -e "${Green}Connecting to host:${Font} $ip"
            # 创建父目录
            ssh -T "$ip" "mkdir -p $(dirname "$absolute_path")"
            # rsync传输文件
            rsync -avz -e ssh "$absolute_path" "$ip:$absolute_path"
        done
    else
        echo "$absolute_path 目录或文件不存在!"
    fi
}


function sync_cmd {
    echo -e "${Green}Execute command.${Font}"
    local cmd="$content"
    # 遍历主机IP列表
    for ip in "${host_ips[@]}"
    do
        echo -e "${Green}Connecting to host:${Font} $ip"
        # 执行命令
        ssh -T "$ip" "$cmd"
    done
}


function parse_ips {
    local in_ips="$1"
    local delim=","
    local range_delim="-"

    if [[ $in_ips == *$delim* ]]; then
        ## 样例:10.0.0.1,10.0.0.2
        host_ips=()
        IFS="$delim" read -ra host_ips <<< "$in_ips"
    elif [[ $in_ips == *$range_delim* ]]; then
        ## 样例:10.0.0.1-5
        
        # 使用“.”拆分IP的4部分
        IFS='.' read -ra ip_parts <<< "$in_ips"
        
        # 拆分第4部分:1-5
        IFS="$range_delim" read -ra range_defi <<< "${ip_parts[3]}"
        
        # IP前3位
        base_ip="${ip_parts[0]}.${ip_parts[1]}.${ip_parts[2]}"
        
        # 开始-结束值
        start=${range_defi[0]}
        end=${range_defi[1]}
        
        # 遍历并加到数组内
        host_ips=()
        for ((i="$start"; i<="$end"; i++)); do
            host_ips+=("$base_ip.$i")
        done
    else
        ## 样例:10.0.0.1
        host_ips=("$in_ips")
    fi
    # 返回数组
    echo "${host_ips[@]}"
    
}


function usage {
    echo -e "${Red}Usage:${Font} $0 {cmd|file} {Command content|File path} [IP|IPs|IP range]"
    echo -e "${Green}rsync.sh: 用于手动同步、分发文件到集群、集群执行命令${Font}"
    echo -e "${Green}cmd: 执行命令${Font}"
    echo -e "${Green}file: 同步文件${Font}"
    echo -e "${Green}Command content: 命令内容,包含空格时使用双引号包括${Font}"
    echo -e "${Green}File path: 文件或者文件夹路径,包含空格时使用双引号包括${Font}"
    echo -e "${Green}IP: 单个ip,例如 10.0.0.177${Font}"
    echo -e "${Green}IPs: 多个ip,例如 10.0.0.176,10.0.0.177${Font}"
    echo -e "${Green}IP range: ip区间,例如 10.0.0.176-177,仅支持ip最后一位区间${Font}"
}


### 开始
# 不输入参数
if [[ "$#" -lt 1 ]]; then
    usage
    exit 0
fi

# 判断是否传入ips
if [[ ! -z "$ips" ]]; then
    host_ips=($(parse_ips "$ips"))
    echo -e "${Green}Use custom IPS:${Font} ${host_ips[@]}"
else
    # 使用默认值
    host_ips=("${default_ips[@]}")
    echo -e "${Green}Use default IPS:${Font} ${host_ips[@]}"
fi

# 判断用途
if [[ "$purpose" == "file" || "$purpose" == "f" ]]; then
    # 同步文件
    sync_file
elif [[ "$purpose" == "cmd" || "$purpose" == "c" ]]; then
    # 执行命令
    sync_cmd
else
    echo -e "${Red}Unknown command:${Font} $purpose"
    usage
    exit 1
fi
rsync.sh使用方法
./rsync.sh {cmd|file} {Command content|File path} [IP|IPs|IP range]
rsync.sh: 用于手动同步、分发文件到集群,集群执行命令
cmd: 执行命令
file: 同步文件
Command content: 命令内容,包含空格时使用双引号包括
File path: 文件或者文件夹路径,包含空格时使用双引号包括
IP: 单个ip,例如 10.0.0.177
IPs: 多个ip,例如 10.0.0.176,10.0.0.177
IP range: ip区间,例如 10.0.0.176-177,仅支持ip最后一位区间