Pexpect,在尝试生成第二个进程时,正在运行ssh-copy-id

时间:2008-12-10 17:16:31

标签: python process pexpect

我正在做一个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 个答案:

答案 0 :(得分:3)

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

您可以尝试使用Paramiko Python SSH2库。这是一个简单的example how to use it with password authentication,然后发出一些shell命令(echo "..." >> $HOME/.ssh/authorized_keys是最简单的)来在远程主机上添加你的公钥。

答案 1 :(得分: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
      

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

  4. 此外,pexpect应该可以与dssh本身一起使用(所以你不需要 使用dssh-agent)。但是使用dssh-agent更简单,更安全。

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

    我不知道这样做的简单方法,OpenSSH ssh-copy-id是 非常挑剔密码的来源......

答案 2 :(得分:0)

阅读pexpect documentation for spawn,我认为它正在等待命令终止。

根据您的需要,我会建议几种不同的可能性:

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对象将会挂起,直到命令终止。

答案 3 :(得分:0)

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

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

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