ssh免密登录是远程自动化执行的前提,需先用ssh-keygen生成密钥对、ssh-copy-id推送公钥并验证成功;执行命令时注意引号使用、tty分配(-t参数)及sudo免密配置。

直接用 ssh 命令就能实现,但必须处理好三件事:免密登录、命令上下文隔离、TTY 分配问题。其他花哨封装(比如 Ansible)是可选的,不是必须的。
确保 ssh 免密码登录已配置
这是所有远程执行的前提。没有它,脚本会卡在密码输入上,无法自动化。
- 在本地生成密钥对:
ssh-keygen -t rsa -b 4096(一路回车即可) - 把公钥推到目标服务器:
ssh-copy-id user@host;如果端口不是 22,加-p 2222 - 验证是否生效:
ssh user@host 'echo ok'应该立刻返回ok,不提示输密码 - 常见坑:
ssh-copy-id失败时别手动复制~/.ssh/id_rsa.pub内容到~/.ssh/authorized_keys—— 容易权限错误;正确做法是用ssh-copy-id自动处理权限
单条或简单多命令用引号包裹 + 分号分隔
适用于 df -h、systemctl status nginx 这类无交互、无状态依赖的命令。
- 基本写法:
ssh user@host "cd /var/log && tail -n 10 app.log" - 多个命令用分号:
ssh user@host "pwd; ls -l /tmp; free -h" - 注意:必须用双引号,单引号会导致本地变量不展开;但若命令里本身要引用变量(如
$HOME),得用单引号或转义:"cd /home/user && echo \$HOME" - 当前工作目录默认是登录用户的家目录,不是你本地脚本所在路径
需要交互或运行 top/vim/sudo 的命令必须加 -t 参数
否则会报错“no tty present”或直接退出,因为 ssh 默认不分配伪终端。
- 正确写法:
ssh -t user@host "sudo systemctl restart nginx" - 如果命令本身要保持交互(如
top或菜单脚本),加一个-t就够;如果遇到仍失败,尝试-tt(强制分配,无视本地是否有 TTY) - 注意:
-t会让 ssh 不自动退出,需手动 Ctrl+C 或等命令自然结束;脚本中慎用于长期运行命令,否则阻塞后续逻辑 - sudo 配置建议:在目标机上运行
visudo,添加%wheel ALL=(ALL) NOPASSWD: /bin/systemctl类规则,避免每次输密码
执行本地脚本或复杂逻辑用 here-document(
适合多行命令、条件判断、临时文件操作等场景,比拼接字符串更清晰、更少引号逃逸问题。
- 示例:
ssh user@host > /dev/null 2>&1 &2 exit 1 fi EOF
- 注意:
中的单引号表示禁用本地变量展开;若需展开本地变量,去掉单引号:<code> - 重定向
> /dev/null 2>&1是为了隐藏输出,但调试阶段建议先去掉,确认逻辑正确后再加 - 结尾的
EOF必须顶格、无空格、无缩进,否则 ssh 会一直等待
最常被忽略的是环境变量差异:远程 shell 通常是 non-interactive non-login shell,不会加载 ~/.bashrc 或 /etc/profile,所以 PATH 可能不含 /usr/local/bin,自定义 alias 也不生效。要么在命令前显式指定完整路径(如 /usr/local/bin/python3),要么在 here-document 开头加 source ~/.bashrc(前提是目标用户真有这个文件且权限正确)。











