在远程服务器上运行本地Python脚本

52

我正在调试一些必须在我的虚拟机上运行的Python脚本。 我更喜欢本地编辑脚本(在虚拟机外部)。 因此,我发现每次将修改后的脚本scp到虚拟机中很繁琐。 有人能建议一些有效的方法吗?

特别是,我想知道是否可能在远程PVM上执行Python脚本。 就像这样:

python --remote user@192.168.1.101 hello.py //**FAKED**, served to explain ONLY
5个回答

73

可以使用ssh来实现。Python接受连字符(-)作为执行标准输入的参数。

cat hello.py | ssh user@192.168.1.101 python -

运行 python --help 以获取更多信息。


10
如果代码包含在子文件夹中的子模块,该怎么办? - Igor Markelov
7
"@Pyaping cat hello.py | ssh user@192.168.1.101 python - arg1 arg2 arg3 对我有效。"该命令表示将本地的hello.py文件通过ssh传输到IP地址为192.168.1.101的远程主机,并在远程主机上使用python解释器运行该文件,并将arg1,arg2和arg3作为脚本的参数传递。 - Stoopkid
1
如果你正在使用 cat a_single_file |,那么你做错了。 - neric
2
如果该Python文件本地包含其他Python模块,则它将无法正常工作。 - KRoy
在执行ssh命令后,它会要求输入密码吗?@asdfg - zircon

54

虽然这个问题不是很新,而且已经有一个答案被选中了,但我想分享另一种好方法。

使用paramiko库——SSH2的纯Python实现——您的Python脚本可以通过SSH连接到远程主机,将自己(!)复制到该主机上,然后在远程主机上执行该副本。远程进程的标准输入、输出和错误输出将在本地运行的脚本上可用。因此,该解决方案与IDE无关。

在我的本地机器上,我使用cmd-line参数“deploy”运行脚本,触发远程执行。如果没有这样的参数,就会运行为远程主机准备的实际代码。

import sys
import os

def main():
    print os.name

if __name__ == '__main__':
    try:
        if sys.argv[1] == 'deploy':
            import paramiko

            # Connect to remote host
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            client.connect('remote_hostname_or_IP', username='john', password='secret')

            # Setup sftp connection and transmit this script
            sftp = client.open_sftp()
            sftp.put(__file__, '/tmp/myscript.py')
            sftp.close()

            # Run the transmitted script remotely without args and show its output.
            # SSHClient.exec_command() returns the tuple (stdin,stdout,stderr)
            stdout = client.exec_command('python /tmp/myscript.py')[1]
            for line in stdout:
                # Process each line in the remote output
                print line

            client.close()
            sys.exit(0)
    except IndexError:
        pass

    # No cmd-line args provided, run script normally
    main()

为了简化这个例子,异常处理被省略了。在有多个脚本文件的项目中,您可能需要将所有这些文件(以及其他依赖项)放在远程主机上。


我可以使用这个结构作为 with open paramiko.SSHClien() ... 以避免忘记 close() 吗? - DiCaprio
1
请检查 len(sys.argv) > 1,否则脚本会在远程端崩溃。此外,您在远程端的 bashrc(或 shell 初始配置)中不能包含任何标准输出打印(bash 中的 echo)。 - Jim M.

30
ssh user@machine python < script.py - arg1 arg2

因为通常不需要使用cat |


5
你可以通过 ssh 来完成它。 ssh user@192.168.1.101 "python ./hello.py" 你也可以使用文本编辑器或 X11 转发在 ssh 中编辑脚本。

17
这会在远程服务器上执行一个 Python 脚本。据我理解,作者希望在远程服务器上执行一个本地的 Python 脚本。 - Sney
是的,你说得对。我也建议通过ssh直接在远程机器上进行编辑,以避免“上传阶段”。 实际上,您可以在一行中上传和执行文件(例如http://unix.stackexchange.com/a/57809)。但是,这个解决方案对我来说看起来有点不干净... - smeso

0

我曾经使用Paramiko做过这样的事情,当时我想在运行了我的OpenVPN服务器并连接到它的ssh服务器上运行一个动态的、本地的PyQt4脚本,并询问他们的路由偏好(分割隧道)。

只要你连接的ssh服务器有你的脚本所需的所有依赖项(在我的情况下是PyQt4),你可以通过将数据编码为base64并在解码后使用exec()内置函数轻松地封装数据。如果我没记错的话,我用一行代码实现了这个:

stdout = client.exec_command('python -c "exec(\\"' + open('hello.py','r').read().encode('base64').strip('\n') + '\\".decode(\\"base64\\"))"' )[1]

这段代码很难阅读,而且你必须转义转义序列,因为它们会被发送者和接收者分别解释两次。它可能还需要一些调试,我已经将我的服务器打包到PCS上了,否则我就可以引用我的OpenVPN路由脚本了。

与发送文件相比,这种方法的不同之处在于它从未触及服务器上的磁盘,而是直接从内存中运行(当然,如果他们记录命令,除外)。你会发现,以这种方式封装信息(虽然效率低下)可以帮助你将数据打包成一个单独的文件。

例如,你可以使用这种方法在主脚本中包含来自外部依赖项(如图像)的原始数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接