封装ssh远程批量执行函数,核心是抽离连接、错误判断、日志和参数传递等重复逻辑,支持免密登录的串行/并发执行、密码登录(慎用)及实用避坑建议。

封装一个用于SSH远程批量执行的Shell函数,核心是把重复逻辑(如连接、错误判断、日志、参数传递)抽离出来,让调用时简洁可靠。不需要每次写一遍ssh命令加判断,也不依赖外部工具如Ansible或expect(除非必须交互式密码)。
基础版:基于免密登录的循环执行函数
前提:已配置好SSH公钥认证(推荐且最安全的方式),目标主机可直接 ssh user@host 执行命令而无需输密码。
- 定义主机列表,支持空格或换行分隔
- 用for循环遍历每台主机,执行同一命令
- 捕获返回值,区分成功/失败并提示
示例函数:
function ssh_batch {
local hosts="$1"
local cmd="$2"
local user="${3:-root}"
for host in $hosts; do
echo "→ 执行 [$cmd] 到 $user@$host"
if ssh "$user@$host" "$cmd" 2>/dev/null; then
echo "✅ $host: 成功"
else
echo "❌ $host: 失败 (exit code: $?)"
fi
done
}
调用方式:ssh_batch "node1 node2 node3" "df -h | grep '/dev/sda'" "deploy"
增强版:带超时、并发与日志记录
生产环境常需控制单次连接时长、避免串行太慢、保留执行痕迹。可用timeout命令限制SSH耗时,用wait配合后台进程实现轻量并发,并统一重定向输出到日志。
- 用
timeout 10s ssh ...防卡死 - 每个ssh任务放后台(&),用
wait等全部结束 - 用
exec >> deploy.log 2>&1集中记录所有输出
关键片段示意:
function ssh_batch_concurrent {
local hosts=($1)
local cmd="$2"
local log_file="${3:-./ssh_batch.log}"
exec >> "$log_file" 2>&1
for host in "${hosts[@]}"; do
(echo "=== $(date) [$host] ==="; timeout 10s ssh "$host" "$cmd") &
done
wait
}
兼容密码登录版(慎用):用sshpass封装
若无法配免密(如临时测试环境),可用sshpass传密码。注意:密码明文出现在脚本或命令行中存在泄露风险,仅限内网低敏场景。
- 先安装
sshpass(Ubuntu/Debian:apt install sshpass) - 函数中用
sshpass -p 'xxx' ssh -o StrictHostKeyChecking=no ... - 建议把密码从环境变量或配置文件读取,避免硬编码
简化调用示例:
function ssh_batch_pass {
local pass="$1"
local hosts="$2"
local cmd="$3"
for host in $hosts; do
sshpass -p "$pass" ssh -o StrictHostKeyChecking=no root@"$host" "$cmd"
done
}
实用建议与避坑点
封装不是越复杂越好,关键是稳定、可读、易维护:
- 主机列表尽量从文件读取(
while read host; do ... done ),方便增删不改脚本 - 远程命令含变量或引号时,用单引号包裹整个命令,或对内部单引号转义;避免本地shell提前解析
- 不要在函数里写
set -e,否则某台失败会中断整个循环;应单独判断$? - 敏感操作(如关防火墙、格式化磁盘)建议加
-n预演模式,或要求确认再执行











