如何通过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
相关产品推荐
相关产品推荐

