#!/bin/bash
# 批量远程命令执行脚本(简化输出版)- 使用expect处理用户切换
# 功能:在预定义的服务器上以root用户执行指定命令,所有输出集中在一个文件
# 使用方法: ./batch_execute.sh "<命令>"
# 示例: ./batch_execute.sh "df -h"
# ====================== 配置区域 ======================
# 硬编码的用户名和密码
USERNAME="lmode"
PASSWORD="FfcsVrt123$%^" # 普通用户密码(用于SSH登录)
ROOT_PASSWORD="Ffcs@2025" # root用户密码(用于su切换)
SSH_PORT=22 # 固定SSH端口
# 硬编码的服务器列表
SERVERS=(
"10.188.21.1"
"10.188.21.2"
)
# ====================== 配置结束 ======================
# 检查参数
if [ $# -lt 1 ]; then
echo "使用方法: $0 \"<命令>\""
echo "示例1: $0 \"uname -a\""
echo "示例2: $0 \"yum update -y\""
exit 1
fi
COMMAND="$1"
# 检查依赖
check_dependency() {
if ! command -v "$1" &> /dev/null; then
echo "错误: 需要安装 $1" >&2
return 1
fi
return 0
}
# 检查必需工具
if ! check_dependency ssh || ! check_dependency sshpass || ! check_dependency expect; then
echo "请安装缺失的工具后重试:"
echo " Ubuntu/Debian: sudo apt install ssh sshpass expect"
echo " CentOS/RHEL: sudo yum install ssh sshpass expect"
exit 1
fi
# 创建输出文件
OUTPUT_FILE="batch_output_$(date +%Y%m%d_%H%M%S).log"
echo "" > "$OUTPUT_FILE" # 创建空文件
# 输出文件头
{
echo "=================================================="
echo "批量执行报告 - $(date)"
echo "命令: $COMMAND"
echo "登录用户: $USERNAME"
echo "执行用户: root"
echo "SSH端口: $SSH_PORT"
echo "服务器列表:"
for server in "${SERVERS[@]}"; do
echo " - $server"
done
echo "=================================================="
echo ""
} | tee -a "$OUTPUT_FILE" # 同时显示在终端并写入文件
# 设置连接超时时间(秒)
SSH_TIMEOUT=15
# 计数器
success_count=0
fail_count=0
total_servers=${#SERVERS[@]}
current_server=0
echo "开始处理 $total_servers 台服务器..."
echo "所有输出将保存到: $OUTPUT_FILE"
echo "--------------------------------------------------" | tee -a "$OUTPUT_FILE"
# 创建临时expect脚本
EXPECT_SCRIPT=$(mktemp)
cat > "$EXPECT_SCRIPT" << EOF
#!/usr/bin/expect -f
# 设置超时时间
set timeout $SSH_TIMEOUT
# 获取参数
set username [lindex \$argv 0]
set password [lindex \$argv 1]
set root_password [lindex \$argv 2]
set ip [lindex \$argv 3]
set command [lindex \$argv 4]
# 不显示spawn命令
log_user 0
# 启动SSH连接
spawn ssh -p $SSH_PORT -o StrictHostKeyChecking=no \$username@\$ip
# 处理连接过程
expect {
timeout {
send_user "连接超时\n"
exit 1
}
"Permission denied" {
send_user "认证失败\n"
exit 1
}
"assword:" {
send "\$password\r"
}
}
# 等待命令提示符
expect {
timeout {
send_user "等待提示符超时\n"
exit 1
}
"*$ " {
# 切换到root
send "su - root\r"
expect {
timeout {
send_user "等待root密码提示超时\n"
exit 1
}
"assword:" {
send "\$root_password\r"
}
}
# 检查是否成功切换到root
expect {
timeout {
send_user "等待root提示符超时\n"
exit 1
}
"*# " {
# 执行命令
send "\$command\r"
# 等待命令完成
expect {
timeout {
send_user "命令执行超时\n"
exit 1
}
-re {^(.*)\r\n.*# $} {
# 捕获命令输出
set command_output \$expect_out(1,string)
send_user "\$command_output\n"
# 退出root会话
send "exit\r"
expect "*$ " {
# 退出SSH会话
send "exit\r"
expect eof
exit 0
}
}
}
}
"Authentication failure" {
send_user "root密码错误\n"
exit 1
}
}
}
}
EOF
chmod +x "$EXPECT_SCRIPT"
# 遍历所有服务器
for ip in "${SERVERS[@]}"; do
((current_server++))
# 输出服务器头信息
{
echo ""
echo "=================================================="
echo "服务器 [$current_server/$total_servers]: $ip"
echo "开始时间: $(date)"
echo "=================================================="
} | tee -a "$OUTPUT_FILE"
# 执行远程命令
echo "执行命令: $COMMAND (作为root用户)" | tee -a "$OUTPUT_FILE"
echo "--------------------------------------------------" | tee -a "$OUTPUT_FILE"
# 使用expect脚本执行命令并捕获输出
OUTPUT=$("$EXPECT_SCRIPT" "$USERNAME" "$PASSWORD" "$ROOT_PASSWORD" "$ip" "$COMMAND" 2>&1)
STATUS=$?
# 显示命令输出
echo "$OUTPUT" | tee -a "$OUTPUT_FILE"
# 检查执行状态
if [ $STATUS -eq 0 ]; then
result="SUCCESS"
((success_count++))
else
result="FAILED (退出码: $STATUS)"
((fail_count++))
fi
# 记录结束状态
{
echo "--------------------------------------------------"
echo "结束时间: $(date)"
echo "执行状态: $result"
echo "=================================================="
} | tee -a "$OUTPUT_FILE"
done
# 清理临时文件
rm -f "$EXPECT_SCRIPT"
# 最终摘要
{
echo ""
echo "=================================================="
echo "执行摘要:"
echo "总服务器数: $total_servers"
echo "成功: $success_count"
echo "失败: $fail_count"
echo "开始时间: $(date -d @$(stat -c %Y "$OUTPUT_FILE"))"
echo "结束时间: $(date)"
echo "输出文件: $OUTPUT_FILE"
echo "=================================================="
} | tee -a "$OUTPUT_FILE"
echo "操作完成! 输出文件: $OUTPUT_FILE"