如何编写Shell脚本实现单主机免密登录多台Linux机器?
如何编写Shell脚本实现主Linux机器免密登录多台目标Linux系统
嘿,这个需求我之前帮不少同行实现过,核心就是自动化完成SSH密钥的生成和批量分发,全程不用手动输密码或者做繁琐的配置。下面给你一步步拆解实现方案:
1. 先搞定自动输密码的工具:sshpass
要自动把公钥传到目标机器,我们得有个工具帮我们自动填登录密码,sshpass就是干这个的。先在你的主机器上安装它:
- 如果你用Debian/Ubuntu这类系统:
sudo apt-get install -y sshpass - 要是RHEL/CentOS或者Fedora:
sudo yum install -y sshpass(新点的系统用dnf也行:sudo dnf install -y sshpass)
2. 准备目标机器列表
先建一个叫target_hosts.txt的文件,把所有要配置的目标机器信息写进去,每行格式是用户名@IP地址 登录密码,比如:
root@192.168.1.100 mySecurePass123 ubuntu@192.168.1.101 ubuntuUserPass456
⚠️ 注意:这个文件存了明文密码,一定要设置好权限,比如chmod 600 target_hosts.txt,别让其他用户看到。
3. 编写自动化脚本
接下来写核心的Shell脚本,命名为auto_ssh_setup.sh,内容如下:
#!/bin/bash # 先检查目标主机列表文件在不在 if [ ! -f "target_hosts.txt" ]; then echo "❌ 出错了:没找到目标主机列表文件 target_hosts.txt!" exit 1 fi # 检查本地有没有SSH密钥对,没有就自动生成(全程无交互) if [ ! -f ~/.ssh/id_rsa ]; then echo "🔧 本地没检测到SSH密钥对,正在自动生成..." ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa echo "✅ 密钥对生成完毕!" fi # 开始批量给目标机器分发公钥 echo "🚀 开始批量配置免密登录..." while read -r host pass; do # 跳过空行 if [ -z "$host" ] || [ -z "$pass" ]; then continue fi echo "正在处理主机:$host" # 用sshpass自动输密码,创建.ssh目录、设置权限,然后把公钥追加到授权文件 sshpass -p "$pass" ssh -o StrictHostKeyChecking=no "$host" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_rsa.pub # 测试一下免密登录是否成功 if ssh -o StrictHostKeyChecking=no "$host" "echo 免密登录测试通过!" > /dev/null 2>&1; then echo "✅ 主机 $host 免密配置成功!" else echo "❌ 主机 $host 配置失败,请检查密码、网络或者SSH服务状态!" fi done < target_hosts.txt echo "🎉 所有主机处理完成!"
4. 运行脚本的步骤
- 先给脚本加执行权限:
chmod +x auto_ssh_setup.sh - 确保
target_hosts.txt和脚本在同一个目录下,内容格式正确 - 直接运行脚本:
./auto_ssh_setup.sh
一些关键细节解释
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa:无交互生成RSA密钥对,-N ""表示密钥本身没有密码短语,这样后续登录不用再输密钥密码-o StrictHostKeyChecking=no:跳过首次登录时的“是否信任该主机”的确认提示,保证脚本全程自动运行mkdir -p ~/.ssh && chmod 700 ~/.ssh:确保目标机器的.ssh目录存在,并且权限是700(只有自己能读写),不然公钥没法生效cat >> ~/.ssh/authorized_keys:把主机器的公钥追加到目标机器的授权文件里,不会覆盖已经存在的其他公钥
额外注意事项
- 目标机器必须开启SSH服务,要是没开的话,先在目标机器上运行
systemctl start sshd(不同系统可能命令略有不同) - 如果目标机器的SSH端口不是默认的22,要在
ssh命令里加上-p 端口号,比如sshpass -p "$pass" ssh -p 2222 -o StrictHostKeyChecking=no "$host" ... - 要是你担心
sshpass明文处理密码的安全问题,也可以考虑用expect工具,但sshpass是最简单直接的方案
内容的提问来源于stack exchange,提问作者Ramesh Das




