You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过subprocess.Popen调用SSH时让远程主机执行本地脚本

如何通过subprocess.Popen调用SSH时让远程主机执行本地脚本

嘿,我来帮你搞定这个问题!你遇到的报错原因很明确:你命令里的< /Users/myself/.../myscript.sh是让远程主机去读取它自己机器上的这个文件,但你的脚本明明在本地,远程当然找不到啦!

下面给你两种靠谱的解决办法,按需选择:

方法一:直接把本地脚本内容通过标准输入传给远程bash

这是最简洁的方式,不需要把脚本传到远程,直接通过管道把脚本内容喂给远程的bash -s(bash -s的作用就是从标准输入读取要执行的代码)。

具体代码修改如下:

import subprocess
import shlex

# 第一步:读取本地脚本的内容
script_path = '/Users/myself/.../myscript.sh'
with open(script_path, 'rb') as f:
    script_content = f.read()

# 第二步:构建SSH命令,注意去掉原来的`< /path/to/script.sh`部分
cmd = 'ssh <hostname> sudo tar xzf <path_to_tar_file> -C <some_directory> && bash -s'
cmd_list = shlex.split(cmd)

# 第三步:启动进程并传递脚本内容
proc = subprocess.Popen(
    cmd_list,
    stdin=subprocess.PIPE,  # 开启管道用于传递输入
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

# 把本地脚本内容传给远程的bash -s
stdout, stderr = proc.communicate(input=script_content)

# 处理执行结果
if proc.returncode != 0:
    print(f"执行出错啦:{stderr.decode('utf-8')}")
else:
    print(f"执行成功,输出:{stdout.decode('utf-8')}")

原理很简单:ssh会把我们通过stdin传入的内容转发给远程主机的bash -s,远程bash直接执行这些内容,完全不需要脚本文件在远程存在。

方法二:先把脚本传到远程再执行

如果你的脚本比较复杂,或者需要在远程保留脚本文件方便调试,可以先通过scp把脚本传到远程临时目录,再执行SSH命令:

import subprocess
import shlex

script_local_path = '/Users/myself/.../myscript.sh'
script_remote_path = '/tmp/myscript.sh'
hostname = '<hostname>'

# 第一步:用scp把本地脚本传到远程
scp_cmd = f'scp {script_local_path} {hostname}:{script_remote_path}'
try:
    subprocess.run(shlex.split(scp_cmd), check=True)
except subprocess.CalledProcessError as e:
    print(f"传文件出错了:{e}")
    exit(1)

# 第二步:执行SSH命令,先解压再执行远程的脚本
ssh_cmd = f'ssh {hostname} sudo tar xzf <path_to_tar_file> -C <some_directory> && bash {script_remote_path}'
proc = subprocess.Popen(shlex.split(ssh_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()

# 可选:执行完后清理远程的脚本文件
cleanup_cmd = f'ssh {hostname} rm {script_remote_path}'
subprocess.run(shlex.split(cleanup_cmd))

# 处理结果
if proc.returncode != 0:
    print(f"执行出错:{stderr.decode('utf-8')}")
else:
    print(f"执行成功:{stdout.decode('utf-8')}")

这种方法的优点是脚本在远程有实体文件,方便排查问题;缺点是多了一步文件传输,需要远程主机有可写的临时目录,而且记得用完清理临时文件哦。

再啰嗦一下为什么原来的命令不行:你原来的命令里的<是远程shell在解析,它会尝试打开远程主机上的/Users/myself/.../myscript.sh,但这个文件只在你本地存在,所以必然报错。

备注:内容来源于stack exchange,提问作者codeforester

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 15:58:06