7

我正在编写一个 Python 脚本,我需要在其中生成几个 ssh-copy-id 进程,并且它们需要我输入密码,所以我使用的是 PExpect。

我基本上有这个:

child = pexpect.spawn('command')
child.expect('password:')
child.sendline('the password')

然后我想产生另一个进程,我不再关心这个了,不管它是否结束。

child = pexpect.spawn('command2')
child.expect('password:')
child.sendline('the password')

并且代码挂在第二个“spawn”

但是,如果我注释掉第一个电话,第二个电话有效,所以我猜测第一个电话仍在运行或某些东西使其无法正常工作。

现在,我无法做的另一件事是等到第一个停止。我试过:
child.close() - 它挂起(以 True 和 False 作为参数) child.read(-1) - 它挂起
child.expect(pexpect.EOF) - 它挂起。
child.terminate() - 它挂起(以 True 和 False 作为参数)

关于可能发生什么的任何想法?
注意:我不是 Python 专家,而且我以前从未使用过 pexpect,所以任何想法都非常受欢迎。

谢谢!


更新:这肯定与 ssh-copy-id 有关,因为对于其他进程,即使它们不返回,spawn 也能正常工作。此外,显然 ssh-copy-id 永远不会返回 EOF。

4

4 回答 4

3

幸运与否,但 OpenSSH 客户端似乎对密码及其来源非常挑剔。

您可以尝试使用Paramiko Python SSH2 库。这是一个简单的示例,如何将其与密码身份验证一起使用,然后发出一些 shell 命令(echo "..." >> $HOME/.ssh/authorized_keys最简单)以在远程主机上添加您的公钥。

于 2009-11-02T18:49:35.387 回答
1

我认为问题在于,SSH 试图打开 PTY,但出于安全原因,它在 PTY 以外的任何东西上都不起作用。这不适用于 pexpect。

我有另一个 ssh 客户端:

http://www.digmia.com/index.php?option=com_content&view=article&id=54:Digmia%20Enterprise%20SSH&Itemid=56

它是开源的,你可以使用它。你想要做的是更多的命令,但你根本不需要期望。

  1. 首先按照手册进行安装,然后执行以下操作:

  2. 运行 dssh-agent,添加您需要的密码,如下所示:

    dssh-add -l < passwordfile
    
    • 或者如果它是一台安全机器,即没有其他人可以在那里登录,这非常重要,否则这将是一个巨大的安全漏洞:

      echo "name-of-server;22;root;password;" | dssh-add -l
      
    • password文件将类似于:

      name-of-server;22;root;password;
      
  3. 并执行类似的操作(替换CONTENTS OF ...为该文件的实际内容):

    dssh root@name-of-server -- echo "CONTENTS OF ~/.ssh/identity.pub" > .ssh/authorized_keys \; chmod og-w .ssh .ssh/authorized_keys
    
    • 你可以(可选)做

      dssh-add -f passwords
      

    (确保没有其他人在做所有这些事情,否则你会有一个竞争条件)。

此外,pexpect 可能应该与 dssh 本身一起使用(因此您不需要使用 dssh-agent)。但是使用 dssh-agent 更简单、更安全。

DSSH 的安装手册包含在 tarball 中。

我不知道任何更简单的方法,OpenSSH ssh-copy-id 对密码的来源非常挑剔......

于 2008-12-10T21:53:02.097 回答
0

阅读spawn 的 pexpect 文档,我认为它正在等待命令终止。

我会根据您的需要提出几种不同的可能性:

1)杀死产生的进程。但是,这可能会导致您的操作腐败,所以我不知道这是否是您想要的。

child = pexpect.spawn('command')
child.expect('password:')
child.sendline('the password')
child.close(True)

2) 等待初始任务完成后再进行下一个任务

child = pexpect.spawn('command')
child.expect('password:')
child.sendline('the password')
child.wait()
child = pexpect.spawn('command2')
...

3)为所有孩子使用不同的实例,然后在最后等待所有孩子——这很可能是最好的解决方案

def exec_command(cmd):
  child = pexpect.spawn(cmd)
  child.expect('password:')
  child.sendline('the password')
  return child

commands = ['command1', 'command2']
childrens = [exec_command(cmd) for cmd in commands]
for child in childrens:
  child.wait()    

注意:这里的所有代码都未经测试,并且是在脚本挂起的假设下编写的,因为删除 spawn 对象将挂起,直到命令终止。

于 2008-12-10T18:10:05.197 回答
0

实际上,我尝试了许多这些替代方法,但都没有奏效。

  • 调用 close() 或 terminate() 挂起(以 True 和 False 作为参数)
  • 调用 wait() 或 read(-1) 或 expect(pexpect.EOF) 挂起
  • 再次调用 spawn 而不关心之前的 spawn 命令挂起

我用其他命令进行了一些测试(比如'ftp',它们按我的预期工作,例如,如果你调用.expect('something'),并且在EOF之前没有找到某些东西,它们不会永远等待,他们抛出一个异常,所以我相信这与 ssh-copy-id 命令特别有关。

于 2008-12-10T18:43:21.963 回答