快速在远程服务器执行命令、批量在多个服务器执行命令(基于sshpass的自定义脚本fastsh)

在日常服务器操作中,很多时候我们需要同时操作多个服务器。特别对于那些每个服务器都需要操作相同命令的场景,不断的切换命令会话窗口会比较麻烦。基于此,编写了本文中的 fastsh 脚本用于轻度解决这种问题,提高一定的便利性。

使用MacOS命令行、LinuxOS命令行、Windows的PowerShell 的情况下,SSH工具都可以免掉,对于服务器临时性操作会特别方便。重度服务器运维还是推荐使用专业的 SSH 工具连接操作。

配置步骤如下:

1、完整的脚本内容见下文,复制内容创建一个 fastsh.sh 脚本。

2、使用命令 chmod +x fastsh.sh 为脚本授可执行权限。

3、在用户的 .bashrc 或系统全局的 profile 文件最下面添加别名设置命令 alias fsh='/path/to/your/fastsh.sh',并使用 source 命令使之生效(例如:source /etc/profile)。

4、打开脚本,在前面前面的 SERVERS 块中维护自己的服务器清单。

5、因为脚本基于 sshpass 组件运行,所有确保服务器已经安装,检查命令 sshpass -V

使用示例

bash 复制代码
#使用参数all,所有服务器都执行命令"ls -l"
fsh all ls -l
#指定具体服务器别名执行命令
fsh s1 ls -l
#指定多个服务器别名执行命令
fsh s1,s3 ls -l

如下是脚本 fastsh.sh 全部内容:

java 复制代码
#!/bin/bash

# 定义包含服务器别名、IP、用户名和密码的数组
declare -a SERVERS=(
    # 添加服务器列表,格式:别名:IP@账号#密码
    "s1:192.168.1.10@root#123456"
    "s2:192.168.1.11@root#123456"
    "s3:192.168.1.21@root#123456789"
)

# 日志文件路径
LOG_FILE="/var/log/fastsh.log"

# 获取客户端IP地址
CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}')
if [[ -z "$CLIENT_IP" ]]; then
    CLIENT_IP="未知客户端IP"
fi

# 日志的公共内容
LOG_MSG_PRE="$(date '+%Y-%m-%d %H:%M:%S') $CLIENT_IP"

# 检查是否提供了足够的参数
if [ $# -lt 2 ]; then
    log_entry="$LOG_MSG_PRE 使用方法: $0 {all|别名[,别名,...]} \"要执行的命令\""
    echo "$log_entry" | tee -a "$LOG_FILE"
    exit 1
fi

# 判断第一个参数是否为 'all' 或者是别名列表
target_all=$1
shift # 移除第一个参数,剩下的作为命令

if [[ "$target_all" == "all" ]]; then
    target_aliases=()
else
    IFS=',' read -r -a target_aliases <<< "$target_all"
fi

# 提取剩余命令行参数作为要执行的命令
COMMAND="$@"

# 初始化变量用于存储匹配到的服务器数量
match_count=0

# 函数:执行命令到指定服务器并记录日志
execute_command() {
    IFS=':' read -r alias ip_user_pass <<< "$1"
    IFS='@#' read -r ip user pass <<< "$ip_user_pass"
    
    # 控制台输出
    console_message="正在执行命令于: $alias ($ip) 使用账户: $user"
    echo "$console_message"
    
    # 日志条目,包括命令内容
    log_entry="$LOG_MSG_PRE $console_message, 命令: $COMMAND"
    echo "$log_entry" >> "$LOG_FILE"
    
    # 执行远程命令(不记录结果到日志文件)
    sshpass -p "$pass" ssh -o StrictHostKeyChecking=no "$user@$ip" "$COMMAND"
    # 执行远程命令(并将结果也记录到日志文件)
    #sshpass -p "$pass" ssh -o StrictHostKeyChecking=no "$user@$ip" "$COMMAND" 2>&1 | while IFS= read -r line; do
    #    echo "$LOG_MSG_PRE $line" >> "$LOG_FILE"
    #    echo "$line"
    #done
}

# 如果指定了 'all',则循环遍历所有服务器执行命令
if [[ ${#target_aliases[@]} -eq 0 ]]; then
    for server in "${SERVERS[@]}"; do
        execute_command "$server"
    done
else
    # 遍历每个服务器并查找匹配项
    matching_servers=()
    for server in "${SERVERS[@]}"; do
        IFS=':' read -r alias ip_user_pass <<< "$server"
        
        for target_alias in "${target_aliases[@]}"; do
            if [[ "$alias" == "$target_alias" ]]; then
                ((match_count++))
                matching_servers+=("$server")
                break
            fi
        done
    done

    # 检查是否有多个匹配或者没有匹配的情况
    if [[ $match_count -gt ${#target_aliases[@]} ]]; then    
        # 控制台输出
        console_message="错误:有多个服务器匹配给定的别名列表 $target_all"
        echo "$console_message"
        log_entry="$LOG_MSG_PRE $console_message"
        echo "$log_entry" >> "$LOG_FILE"
        exit 1
    elif [[ $match_count -eq 0 ]]; then
        console_message="错误:没有找到匹配给定的别名列表 $target_all"
        echo "$console_message"
        log_entry="$LOG_MSG_PRE $console_message"
        echo "$log_entry" >> "$LOG_FILE"
        exit 1
    else
        # 如果找到了匹配则执行命令
        for server in "${matching_servers[@]}"; do
            execute_command "$server"
        done
    fi
fi

脚本记录的日志在 /var/log/fastsh.log 中,包含执行命令的时间、会话用户IP地址及执行的命令。

bash 复制代码
[root@test opt]# tail -f /var/log/fastsh.log 
2024-12-15 11:02:49 10.7.0.2 错误:没有找到匹配给定的别名列表 23
2024-12-15 11:25:34 10.7.0.2 使用方法: ./fastsh {all|别名[,别名,...]} "要执行的命令"
2024-12-15 11:25:46 10.7.0.2 正在执行命令于: 10 (192.168.1.10) 使用账户: root, 命令: ls

(END)

相关推荐
库玛西21 小时前
深入浅出传输层:UDP 与 TCP 协议全景指南
linux·服务器·网络·c++·笔记·tcp/ip·udp
随便做点啥21 小时前
32卡-64G-910B4-16后端-(Qwen3.8-27B-W8A8)集群部署报告
运维·服务器·经验分享·docker·vllm
2601_962218471 天前
万象生鲜系统区块链溯源技术帮助生鲜企业搭建食品安全数字化体系
大数据·运维·微服务·云原生·架构
智塑未来1 天前
中小公司在线文档选型:从协作入口到安全边界
运维·安全
新时代牛马1 天前
Linux 内核入门地图:架构、源码目录与五大子系统
linux·运维·架构
智购科技无人售货机厂家1 天前
2026自动售货机制冷系统维护指南:从散热器清洁到压缩机换油的工程实践~YH
运维·redis·物联网·缓存·架构
剑客的茶馆1 天前
开发者,运维怎样转行FDE?
运维·ai·开发·fde
Julien20041 天前
控制 SELinux 文件上下文
linux·运维·服务器
sulikey1 天前
Linux Core Dump 完全指南:从原理到实战的崩溃调试手册。什么是core dump?程序报错core dumped怎么办?
linux·服务器·操作系统·调试·coredump
Lifangyun_WD1 天前
第一次租 GPU 服务器怎么开始?镜像、SSH、数据存储和停机前要做什么
服务器·云计算·gpu算力·gpu算力租赁