远程服务器上的子进程

时间:2015-07-17 13:26:58

标签: python ssh command subprocess

我正在使用此代码在远程服务器上执行命令。

import subprocess
import sys
COMMAND="ls"

ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
                   shell=False,
                   stdout=subprocess.PIPE,
                   stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
    error = ssh.stderr.readlines()
    print >>sys.stderr, "ERROR: %s" % error
else:
    print result

当我尝试执行此脚本时,会收到密码提示。有什么方法可以避免它,例如,我可以以某种方式在脚本中输入密码吗?此外,密码应以某种方式加密,以便有权访问该脚本的人无法看到它。

7 个答案:

答案 0 :(得分:4)

一种方法是创建公钥,将其放在服务器上,然后执行ssh -i /path/to/pub/key user@host或使用paramiko,如下所示:

import paramiko
import getpass

ssh = paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

p = getpass.getpass()

ssh.connect('hostname', username='user', password=p)

stdin, stdout, stderr = ssh.exec_command('ls')
print stdout.readlines()
ssh.close()

答案 1 :(得分:2)

您应该使用pexpectparamiko连接到远程计算机,然后生成一个孩子,然后运行subprocess以达到您想要的效果。

答案 2 :(得分:2)

以下是我在遇到此问题时所做的事情:

  1. 设置ssh密钥以访问服务器。
  2. Set up an alias for the server you're accessing。下面我称之为remote_server
  3. 将以下两行放在~/.bash_profile的末尾。

    eval $(ssh-agent -s)
    ssh-add
    
  4. 现在每次启动shell时,系统都会提示您输入密码。输入后,您将对您的ssh密钥进行身份验证并将其放入手中'在你的bash会话开始时。对于会话的剩余部分,您将能够运行

    之类的命令
        ssh remote_server ls
    

    没有提示输入密码。此处ls将在远程服务器上运行并将结果返回给您。同样,如果从shell执行它,你的python脚本应该在没有密码提示中断的情况下运行。

    您只需输入ssh remote_server即可直接登录到服务器,而无需每次都输入您的用户名或密码。

    这样做的好处是你应该这样做,以避免密码烦恼和记住时髦的服务器名称:)此外,你不必担心在脚本的任何地方保存密码。唯一可能的缺点是,如果你想与其他人共享python脚本,他们也必须进行这种配置(他们应该这样做)。

答案 3 :(得分:1)

虽然subprocess.Popen可能适用于ssh访问权限,但这不是首选方式。

我建议使用paramiko

import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(server, username=user,password=password)
...
ssh_client.close()

如果您想模拟终端,就像用户输入一样:

chan=ssh_client.invoke_shell()

def exec_cmd(cmd):
    """Gets ssh command(s), execute them, and returns the output"""
    prompt='bash $' # the command line prompt in the ssh terminal
    buff=''
    chan.send(str(cmd)+'\n')
    while not chan.recv_ready():
        time.sleep(1)
    while not buff.endswith(prompt):
        buff+=ssh_client.chan.recv(1024)
    return buff[:len(prompt)]

使用示例:exec_cmd('pwd')

如果您事先不知道提示,可以使用以下方式进行设置:

chan.send('PS1="python-ssh:"\n')

答案 4 :(得分:1)

你真的不需要像pexpect这样的东西来处理这个问题。 SSH密钥已经为这类问题提供了非常好的安全解决方案。

获得所需结果的最简单方法可能是生成一个ssh密钥并将其放在设备的.ssh文件夹中。如果你研究一下,我相信github有很好的指导。在两个系统上正确设置密钥后,您实际上不必在代码中添加一行。如果您没有指定密码,它将自动使用密钥对您进行身份验证。

答案 5 :(得分:1)

为什么要这么复杂?这是我的建议:

1)在〜/ .ssh / config文件中创建一个ssh config部分:

Host myserver
  HostName 50.50.50.12 (fill in with your server's ip)
  Port xxxx (optional)
  User me (your username for server)

2)如果您已经生成了ssh密钥对,请立即执行(使用ssh-keygen)。然后上传:

$ ssh-copy-id myserver

3)现在您可以将子进程与ssh一起使用。例如,要捕获输出,我调用:

result = subprocess.check_output(['ssh', 'myserver', 'cat', 'somefile'])

简单,健壮,并且只有在需要密码时才将公钥复制到服务器。

顺便说一下,使用这些步骤,您的代码可能也会正常工作。

答案 6 :(得分:0)

您可以使用以下内容。

import subprocess
import sys
COMMAND="ls"

ssh = subprocess.Popen("powershell putty.exe user@HOST -pw "password", stdout=PIPE, stdin=PIPE, stderr=STDOUT)
result = ssh.stdout.readlines()
if result == []:
    error = ssh.stderr.readlines()
    print >>sys.stderr, "ERROR: %s" % error
else:
    print result