【问题标题】:Verify a file exists over ssh通过 ssh 验证文件是否存在
【发布时间】:2011-01-12 15:24:22
【问题描述】:

我正在尝试使用 pexpect 通过 SSH 测试文件是否存在。我已经让大部分代码工作了,但我需要捕获该值,以便我可以断言文件是否存在。我做的代码如下:

def VersionID():

        ssh_newkey = 'Are you sure you want to continue connecting'
        # my ssh command line
        p=pexpect.spawn('ssh service@10.10.0.0')

        i=p.expect([ssh_newkey,'password:',pexpect.EOF])
        if i==0:
            p.sendline('yes')
            i=p.expect([ssh_newkey,'password:',pexpect.EOF])
        if i==1:
            p.sendline("word")
            i=p.expect('service@main-:')
            p.sendline("cd /opt/ad/bin")
            i=p.expect('service@main-:')
            p.sendline('[ -f email_tidyup.sh ] && echo "File exists" || echo "File does not exists"')
            i=p.expect('File Exists')
            i=p.expect('service@main-:')
            assert True
        elif i==2:
            print "I either got key or connection timeout"
            assert False

        results = p.before # print out the result

VersionID()

感谢您的帮助。

【问题讨论】:

  • @chrissygormley - 我不认为你会考虑使用 ssh-agent 来存储你的密码?如果你这样做了,你可以完全避免 pexpect 而只是这样做: ssh user@host "command"
  • 我已经在下面发布了我对这个问题的回答。谢谢

标签: python bash testing ssh pexpect


【解决方案1】:

为什么不利用命令的返回码通过 SSH 传回这一事实呢?

$ ssh victory 'test -f .bash_history'
$ echo $?
0
$ ssh victory 'test -f .csh_history'
$ echo $?
1
$ ssh hostdoesntexist 'test -f .csh_history'
ssh: Could not resolve hostname hostdoesntexist: Name or service not known
$ echo $?
255

这样,您可以只检查返回码而不需要捕获输出。

【讨论】:

  • (是的,我是用 shell 脚本编写的……用 Python 编写代码留给读者作为练习 :))
【解决方案2】:

如果服务器接受 sftp 会话,我不会打扰 pexpect,而是使用 Python 的 paramiko SSH2 模块:

import paramiko
transport=paramiko.Transport("10.10.0.0")
transport.connect(username="service",password="word")
sftp=paramiko.SFTPClient.from_transport(transport)
filestat=sftp.stat("/opt/ad/bin/email_tidyup.sh")

代码打开一个到服务器的SFTPClient 连接,您可以在该连接上使用 stat() 检查文件和目录是否存在。

当文件不存在时,sftp.stat 将引发 IOError ('No such file')。

如果服务器不支持 sftp,这会起作用:

import paramiko
client=paramiko.SSHClient()
client.load_system_host_keys()
client.connect("10.10.0.0",username="service",password="word")
_,stdout,_=client.exec_command("[ -f /opt/ad/bin/email_tidyup.sh ] && echo OK")
assert stdout.read()

SSHClient.exec_command 返回一个三元组 (stdin,stdout,stderr)。在这里,我们只检查是否存在任何输出。您可以改为更改命令或检查 stderr 是否有任何错误消息。

【讨论】:

  • @flight -- 我得到一个错误:----paramiko.SSHException: Channel closed.---- 所有细节都输入正确,你知道为什么吗?谢谢
  • @chrissygormley:“sftp service@10.10.0.0”是否适合您(即在 shell 中)?
  • @flight -- sftp 确实适用于其他机器,但对于我正在登录的相机,它被拒绝了。我将看看如何解决这个问题并再次尝试上面的代码。谢谢
  • 相机上可能不存在 sftp 二进制文件。尝试使用 ssh 或 sftp 和 -v
  • @chrissygormley:我很想知道第二种解决方案(没有 SFTP,见上文)是否适合您。
【解决方案3】:

我遇到了一些问题,每次我运行我的程序时,它都会改变输出。例如如果我正在寻找/bin/bash,它有时会返回它已找到,有时它会返回它丢失。

通过在\r\n 之前预期的内容,我得到以下代码以一致地用于文件和文件夹

# returns 0 if the file is missing and 1 if the file exists
# if ( hostFileExists( host, '/bin/sh/' ) == 1 ): echo "File exists!"
def hostFileExists( host, theFile ):
    host.sendline( '[ ! -e %r ] && echo NO || echo YES' % theFile )
    return host.expect( ["\r\nNO", "\r\nYES"] )

# provide the host, the command, and the expectation
# command = '[ ! -e "/bin/sh" ] && echo NO || echo YES'
# expecting = ['NO', 'YES']
# i = hostExpect( host, command, expecting )
# if ( i == 1 ): echo "File exists!"
def hostExpect( host, command, expect ):
    newExpect = []
    for e in expect:
        newExpect.append( "\r\n%s" % e )
    host.sendline( command )
    return host.expect( newExpect )

希望对你有所帮助。

编辑:还注意到当 ssh 进入 Windows (cygwin) 并尝试查看文件是否存在时,必须引用该文件。在 Linux 上,这是可选的。所以host.sendline中的%s改成了%r

【讨论】:

    【解决方案4】:

    我没有任何 pexpect 经验,但查看他们的网页,您似乎可以使用多个值调用 expect 方法,并返回它匹配的索引(这纯粹是基于我只是看着这个例子)。

    child.expect('password:')
    child.sendline (my_secret_password)
    # We expect any of these three patterns...
    i = child.expect (['Permission denied', 'Terminal type', '[#\$] '])
    if i==0:
        print 'Permission denied on host. Can't login'
        child.kill(0)
    elif i==2:
        print 'Login OK... need to send terminal type.'
        child.sendline('vt100')
        child.expect ('[#\$] ')
    elif i==3:
        print 'Login OK.'
        print 'Shell command prompt', child.after
    

    实际上,您已经在顶部使用了该功能。

    所以你想知道文件是否存在?...

    试试这个...

            p.sendline('[ -f email_tidyup.sh ] && echo "File exists" || echo "File does not exists"')
            file_exists = {0: True, 1: False}[p.expect(('File Exists', 'File does not exists'))]
    

    【讨论】:

    • 我已经尝试过了,但它不起作用,因为 p.expect 不允许元组?
    【解决方案5】:

    我已经找到了适合我的解决方案。代码如下:

    def VersionID(): 
    
        ssh_newkey = 'Are you sure you want to continue connecting' 
        # my ssh command line 
        p=pexpect.spawn('ssh service@10.10.0.0') 
    
        i=p.expect([ssh_newkey,'password:',pexpect.EOF]) 
        if i==0: 
            p.sendline('yes') 
            i=p.expect([ssh_newkey,'password:',pexpect.EOF]) 
        if i==1: 
            p.sendline("word") 
            i=p.expect('service@main-:') 
            p.sendline("cd /opt/ad/bin") 
            i=p.expect('service@main-:') 
            p.sendline('[ -f email_tidyup.sh ] && echo "File exists" || echo "File does not exists"') 
            i=p.expect('service@main-:') 
            assert True 
        elif i==2: 
            print "I either got key or connection timeout" 
            assert False 
    
    
            results = p.before # print out the result
            print results
            value = results.split('"')[8]
            split_value = value.split('\r\n')[1:-1]
            self.assertEquals(split_value, ['File exists'])
    

    这会以字符串格式从“p”中提取值。然后,我将字符串拆分以将字符串“文件存在”放入一个列表中,并将其与我正在寻找的响应进行比较。如果文件不存在,则测试将失败。

    感谢大家的帮助。

    【讨论】:

      【解决方案6】:

      当您作为用户在 ssh 中键入内容时,shell 会回显这些字符。现在也正在发生这种情况。

      所以,做:

      p.sendline('test -f email_tidyup.sh && echo "File exists" || echo "File does not exist"')
      

      将导致输入:

      service@main-: test -f email_tidy.sh && echo "File exists" || echo "File does not exists"
      File does not exist
      

      在做:

      i = p.expect(['File exists', 'File does not exist'])
      

      然后将始终导致 i==0,因为“文件存在”出现在接收回的第一行中。

      原始发送行没有预期句子的替代方案:

      p.sendline('test -f email_tidyup.sh; echo result: $?')
      i = p.expect('result: 0', 'result: 1')
      

      或者更像原版:

      p.sendline('[ -f email_tidyup.sh ] && echo "File exists" || echo "File does not exist"')
      i = p.expect(['\nFile exists', '\nFile does not exist'])
      

      【讨论】:

      • @Johan 我尝试了您提供的解决方案。当文件存在时 i==0 但文件不存在时 i==0 也是如此。
      • 方括号版本与test版本完全相同
      • @Dennis 你是对的。我已经从答案中删除了那部分。
      猜你喜欢
      • 1970-01-01
      • 2023-04-08
      • 2013-02-06
      • 2021-07-23
      • 2020-03-20
      • 2019-12-26
      • 2019-01-01
      • 2021-03-25
      • 1970-01-01
      相关资源
      最近更新 更多