脚本中SSH远程执行有哪些方式

wen 实用脚本 2

本文目录导读:

脚本中SSH远程执行有哪些方式

  1. 核心方式对比
  2. 直接命令模式(最常用)
  3. 本地脚本管道模式(推荐较复杂逻辑)
  4. 远程执行文件模式(依赖本地文件)
  5. 交互式自动化模式(处理密码登录)
  6. 高级工具封装模式(批量与编排)
  7. 核心注意事项
  8. 选择建议

在脚本中通过SSH远程执行命令,主要有以下几种方式,它们的核心区别在于是否需要交互、是否占用终端以及如何传递密码。

核心方式对比

方式 核心命令 / 工具 是否需要交互 密码处理 典型场景
直接命令模式 ssh user@host command 需密钥或expect 执行单条或简单命令
本地脚本管道 cat script.sh \| ssh user@host 需密钥或expect 执行较复杂的脚本逻辑
远程执行文件 scp + ssh 组合 需密钥或expect 依赖本地文件或需要持久化脚本
交互式自动化 expect / sshpass 明文或自动输入 环境不支持密钥,必须密码登录
高级工具封装 Ansible, Fabric, Paramiko 多种方式 大批量、复杂编排、需要幂等性

直接命令模式(最常用)

直接在 ssh 命令后面加上要执行的命令,SSH 会执行完毕后自动退出。

# 基础语法
ssh user@host "command1; command2; command3"
# 示例:查看远程磁盘空间
ssh root@192.168.1.100 "df -h"
# 示例:在远程执行带变量的命令(需注意引号转义)
ssh user@host 'echo "Hostname: $(hostname); Date: $(date)"'
# 示例:在远程执行需要 sudo 权限的命令
ssh -t user@host "sudo systemctl restart nginx"
# -t 参数强制分配伪终端,解决 sudo 可能提示 "no tty present" 的问题

优缺点

  • ✅ 简单直接,无需额外脚本。
  • ❌ 复杂逻辑(if/for 循环)写起来繁琐,转义复杂。

本地脚本管道模式(推荐较复杂逻辑)

将本地脚本文件的内容通过管道发送到远程主机的 shell 中执行。

# 本地脚本 local_script.sh
#!/bin/bash
echo "=== System Info ==="
uname -a
echo "=== Disk Usage ==="
df -h
# 通过管道远程执行
cat local_script.sh | ssh user@host bash
# 也可以直接使用 heredoc(无需单独脚本文件)
ssh user@host bash << 'EOF'
for i in {1..5}; do
    echo "Iteration $i"
    uptime
done
EOF
# 注意:EOF 用单引号括起来表示禁止本地shell解析变量,否则会先被本地替换

优缺点

  • ✅ 适合执行多步、含循环/判断的复杂逻辑。
  • ❌ 脚本标准错误和标准输出混合,调试稍微困难(可通过重定向解决)。

远程执行文件模式(依赖本地文件)

先将本地脚本或文件上传到远程主机,再通过 SSH 执行该文件。

# 1. 上传脚本
scp /path/to/script.sh user@host:/tmp/script.sh
# 2. 远程执行
ssh user@host "bash /tmp/script.sh"
# 3. 清理远程文件(可选)
ssh user@host "rm /tmp/script.sh"
# 或者合并为一行
scp script.sh user@host:/tmp/script.sh && ssh user@host "bash /tmp/script.sh && rm /tmp/script.sh"

优缺点

  • ✅ 脚本可以依赖本地附件,执行结果可控,适合批量分发。
  • ❌ 多了一步上传操作,稍微慢一点。

交互式自动化模式(处理密码登录)

当无法配置 SSH 密钥时,需要自动输入密码。

方式 A:使用 sshpass(最简单)

# 安装:apt install sshpass / yum install sshpass
sshpass -p 'your_password' ssh user@host "command"
# 注意:密码明文,安全性较低,不推荐生产环境
# 可通过环境变量稍微提高安全性(但仍不完美)
export SSHPASS='your_password'
sshpass -e ssh user@host "command"

方式 B:使用 expect(最灵活)

#!/usr/bin/expect
set timeout 10
spawn ssh user@host
expect "password:"
send "your_password\r"
expect "$ "
send "ls -la\r"
expect "$ "
send "exit\r"
expect eof

优缺点

  • ✅ 能解决一切交互式登录问题,特别适合跳板机、二次认证等场景。
  • sshpass 密码明文,expect 脚本维护成本较高。

高级工具封装模式(批量与编排)

Ansible(无需 agent,SSH 底层)

- name: 远程执行命令
  hosts: webservers
  tasks:
    - name: Check disk usage
      shell: df -h
      register: result
    - debug: var=result.stdout_lines
ansible webservers -m shell -a "df -h"

Fabric(Python 库)

from fabric import Connection
with Connection("user@host") as c:
    result = c.run("uname -a", hide=True)
    print(result.stdout)

Paramiko(纯 Python SSH 库)

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("host", username="user", password="pass")
stdin, stdout, stderr = client.exec_command("df -h")
print(stdout.read().decode())
client.close()

核心注意事项

  1. 优先使用 SSH 密钥登录,避免密码明文出现在脚本或日志中。
  2. 环境变量差异:通过 ssh 执行命令时,不会加载 .bashrc.profile,需手动指定或使用 source ~/.bashrc
    ssh user@host "source ~/.bashrc && command"
  3. 引号转义:复杂命令建议用单引号包裹整个远程命令,防止本地 shell 先解析。
    • 本地变量:ssh user@host "echo $HOME"(输出本地 HOME)
    • 远程变量:ssh user@host 'echo $HOME'(输出远程 HOME)
  4. 标准输入重定向:如果脚本需要通过 STDIN 接收输入,需注意管道和 SSH 的 STDIN 冲突。
  5. 错误处理:默认 SSH 远程命令返回码仅代表远程命令的退出码,建议在脚本中加上 set -e 或检查 。
  6. 多命令执行顺序:使用 、&&、 控制逻辑,用 或 分组。

选择建议

场景 推荐方式
简单单条命令 方式1:直接 ssh user@host "command"
复杂循环/条件逻辑 方式2:本地脚本管道 cat script \| ssh ...
需要上传文件后执行 方式3:scp + ssh 组合
无法使用密钥,必须密码 方式4:sshpass(低安全)或 expect(高控制)
批量管理大量服务器 方式5:Ansible
需要集成到 Python 应用 方式5:Paramiko / Fabric

抱歉,评论功能暂时关闭!