Linux 中 SSH 远程执行命令:从基础到实战
概述
SSH(Secure Shell,安全外壳协议)是基于应用层的加密网络协议,核心价值在于为远程登录、文件传输及命令执行等操作提供端到端的安全保障 —— 通过非对称加密、数据完整性校验等机制,可有效避免远程管理过程中的信息泄露、数据篡改等风险。
最初,SSH 仅作为 UNIX 系统的远程管理工具,如今已成为跨平台(Linux、macOS、Windows 等)的标准远程协议。除了最常用的 “远程登录服务器” 功能外,SSH 最强大的能力之一是直接远程执行命令 / 脚本,这为自动化运维(如批量服务器配置、定时任务执行)提供了关键技术支撑。
1. 远程执行单行 / 多行命令
适用于命令逻辑简单、无需交互的场景(如查看服务器状态、创建单个文件等),核心是通过引号将多条命令包裹,用分号(;)分隔命令执行顺序。
语法格式
# 单行命令(直接执行)
ssh $username@$ip "single_command"
# 多行命令(用分号分隔,按顺序执行)
ssh $username@$ip "command1; command2; command3"
实战示例
# 1. 远程查看目标服务器的系统版本(单行命令)
ssh root@192.168.1.100 "cat /etc/os-release"
# 2. 远程创建目录→新建文件→写入内容(多行命令)
ssh roger@192.168.1.101 "mkdir -p /home/roger/test; cd /home/roger/test; echo 'SSH remote test' > test.txt"
注意事项
- 若命令中包含特殊字符(如 $、*、>),需用单引号包裹命令,避免本地 Shell 提前解析变量(例如:ssh user@ip 'echo $PATH' 会输出远程服务器的 PATH,而双引号会输出本地 PATH)。
- 分号(;)表示 “无论前一条命令是否成功,都执行下一条”;若需 “前一条成功才执行下一条”,可改用 &&(例如:command1 && command2)。
2. 远程执行交互命令
当命令需要用户交互(如 sudo 输入密码、vim 编辑文件、top 查看进程)时,直接执行会因 “无终端交互环境” 失败,需添加 -t 参数强制为 SSH 会话分配伪终端(pseudo-tty)。
语法格式
ssh -t $username@$ip "interactive_command"
实战示例
# 1. 远程执行 sudo 命令(需输入密码交互)
ssh -t roger@192.168.1.100 "sudo apt update"
# 2. 远程使用 top 查看进程(需终端交互操作)
ssh -t root@192.168.1.101 "top"
关键说明
- -t 参数的作用是 “告诉 SSH 客户端:需要模拟一个本地终端,让远程命令能获取到交互输入”,若无此参数,sudo 会提示 “抱歉,无法通过 sudo 获得密码,因为没有终端”。
- 若需多次交互(如连续执行多个需要密码的命令),可添加 -tt(双 -t)参数,确保终端交互的稳定性。
3. 远程执行命令时传入本地变量
当需要将本地 Shell 变量(如本地定义的文件名、时间戳)传递到远程命令中时,需注意变量解析的上下文(避免被本地 Shell 提前替换)。
语法格式(两种可靠方式)
# 方式1:用 bash -c 接收命令,本地变量用双引号包裹(推荐)
local_var="hello_ssh"
ssh $username@$ip bash -c "'echo $local_var'"
# 方式2:用单引号包裹远程命令,变量部分用双引号拆分(更直观)
ssh $username@$ip 'echo "'$local_var'"'
实战示例
# 本地定义文件名称,远程创建对应文件
file_name="remote_file_$(date +%Y%m%d).txt"
ssh roger@192.168.1.100 bash -c "'touch /home/roger/$file_name'"
# 执行后远程会生成类似 "remote_file_20240520.txt" 的文件
常见坑点
- 若直接写 ssh user@ip "echo $local_var",本地 Shell 会先将 $local_var 替换为本地值,再传递给远程,看似能生效,但当命令包含复杂逻辑(如循环、条件判断)时会解析混乱,推荐统一用 bash -c 方式。
4. 远程执行本地脚本(不带参数)
当需要执行的命令逻辑复杂(如多步骤部署、批量处理)时,单独写远程命令会难以维护,此时可将逻辑封装为本地脚本,通过 SSH 直接传递给远程服务器执行(无需先上传脚本)。
语法格式
# 本地脚本路径为 local_script.sh,通过输入重定向(<)传递给远程
ssh $username@$ip < local_script.sh
实战示例
- 本地创建脚本 local_deploy.sh(示例:远程安装 Nginx 依赖):
#!/bin/bash
# 本地脚本:远程执行安装依赖操作
echo "开始在远程服务器安装依赖..."
sudo apt update && sudo apt install -y gcc g++ make libpcre3-dev zlib1g-dev
echo "依赖安装完成!"
- 赋予脚本执行权限并远程执行:
# 本地赋予权限
chmod +x local_deploy.sh
# 远程执行本地脚本(无需上传脚本到远程)
ssh -t roger@192.168.1.100 < local_deploy.sh
关键说明
- 脚本开头必须指定解释器(如 #!/bin/bash),否则远程服务器可能用默认的 sh 执行,导致语法兼容问题(如 [[]] 表达式在 sh 中不支持)。
- 若脚本包含 sudo 等交互命令,需搭配 -t 参数(参考 “远程执行交互式命令” 章节)。
5. 远程执行本地脚本(带参数)
若本地脚本需要动态传入参数(如环境变量、目标路径),需在传递脚本的同时,通过 bash -s 让远程 Bash 接收参数(-s 表示 “从标准输入读取脚本内容”,参数后续传入)。
语法格式
# local_script.sh 是本地脚本,$param1 $param2 是要传递的参数
ssh $username@$ip 'bash -s' < local_script.sh $param1 $param2
实战示例
- 本地创建带参数的脚本 local_backup.sh(示例:远程备份指定目录):
#!/bin/bash
# 本地脚本:接收2个参数(备份源目录、备份目标路径)
src_dir=$1 # 第1个参数:要备份的目录
dest_path=$2 # 第2个参数:备份文件保存路径
echo "开始备份远程目录 $src_dir ..."
tar -zcf $dest_path/backup_$(date +%H%M%S).tar.gz $src_dir
echo "备份完成!文件保存至 $dest_path"
- 本地执行远程脚本并传参:
# 传递参数:1. 远程要备份的目录 /var/log;2. 备份保存路径 /home/roger/backups
ssh -t roger@192.168.1.100 'bash -s' < local_backup.sh /var/log /home/roger/backups
6. 远程执行远程服务器上的脚本(不带参数)
若脚本已提前部署到远程服务器(如通过 CI/CD 工具上传、手动放置),直接通过 SSH 指定远程脚本的绝对路径即可执行(无需传递本地文件)。
语法格式
# 必须指定远程脚本的绝对路径(如 /home/roger/remote_script.sh)
ssh $username@$ip /path/to/remote_script.sh
实战示例
# 远程脚本已存在于 /home/roger/clean_logs.sh(功能:清理7天前的日志)
ssh roger@192.168.1.100 /home/roger/clean_logs.sh
注意事项
- 必须用绝对路径:远程 Shell 的 PATH 环境变量可能不包含脚本所在目录(如脚本在用户家目录,但 PATH 未包含 ~/),直接写脚本名会提示 “命令不存在”。
- 确保脚本有执行权限:若远程脚本无权限,需先执行 ssh user@ip "chmod +x /path/to/remote_script.sh" 赋予权限。
7. 远程执行远程服务器上的脚本(带参数)
与 “本地脚本传参” 逻辑类似,远程脚本接收参数时,直接在脚本路径后追加参数即可,远程 Bash 会自动将参数传递给脚本。
语法格式
# 远程脚本路径 + 空格 + 参数1 + 空格 + 参数2
ssh $username@$ip /path/to/remote_script.sh $param1 $param2
实战示例
- 远程脚本 remote_copy.sh(已存在于 /home/roger/,功能:复制文件到指定目录):
#!/bin/bash
# 远程脚本:接收2个参数(源文件、目标目录)
src_file=$1
dest_dir=$2
if [ -f $src_file ]; then
cp $src_file $dest_dir
echo "文件 $src_file 已复制到 $dest_dir"
else
echo "错误:源文件 $src_file 不存在!"
fi
- 本地执行远程脚本并传参:
# 传递参数:1. 远程源文件 /home/roger/test.txt;2. 目标目录 /tmp
ssh roger@192.168.1.100 /home/roger/remote_copy.sh /home/roger/test.txt /tmp
总结
SSH 远程执行命令 / 脚本是 Linux 运维的核心技能之一,不同场景对应不同的实现方式,核心是明确 “命令 / 脚本的位置”(本地 / 远程)和 “是否需要交互 / 传参”,以下是场景与方案的对应表,可直接参考:
需求场景 | 推荐方案 | 关键参数 / 注意点 |
---|---|---|
简单单行 / 多行命令(无交互) | ssh user@ip "cmd1; cmd2" | 复杂命令用单引号,避免本地解析 |
交互式命令(如 sudo、top) | ssh -t user@ip "interactive_cmd" | 必须加 -t 分配伪终端 |
传递本地变量到远程 | ssh user@ip bash -c "'echo $var'" | 用 bash -c 确保变量正确传递 |
执行本地脚本(无参数) | ssh user@ip < local_script.sh | 脚本需指定解释器(#!/bin/bash) |
执行本地脚本(带参数) | ssh user@ip 'bash -s' < local_script.sh param | bash -s 接收脚本,参数后置 |
执行远程已存在的脚本 | ssh user@ip /path/to/remote_script.sh | 必须用绝对路径,确保脚本有权限 |