bash 通过 ssh 验证文件存在

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2192442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 21:37:48  来源:igfitidea点击:

Verify a file exists over ssh

pythonbashtestingsshpexpect

提问by chrissygormley

I am trying to test if a file exists over SSH using pexpect. I have got most of the code working but I need to catch the value so I can assert whether the file exists. The code I have done is below:

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

def VersionID():

        ssh_newkey = 'Are you sure you want to continue connecting'
        # my ssh command line
        p=pexpect.spawn('ssh [email protected]')

        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()

Thanks for any help.

谢谢你的帮助。

采纳答案by flight

If the server accepts sftp sessions, I wouldn't bother with pexpect, but instead use the paramikoSSH2 module for Python:

如果服务器接受 sftp 会话,我不会理会 pexpect,而是使用Python的paramikoSSH2 模块:

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")

The code opens an SFTPClientconnection to the server, on which you can use stat() to check for the existance of files and directories.

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

sftp.stat will raise an IOError ('No such file') when the file doesn't exist.

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

If the server doesn't support sftp, this would work:

如果服务器不支持 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 returns a triple (stdin,stdout,stderr). Here we just check for the presence of any output. You might instead vary the command or check stderr for any error messages instead.

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

回答by MikeyB

Why not take advantage of the fact that the return code of the command is passed back over SSH?

为什么不利用命令的返回码通过 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

This way, you can just check the return code without needing to capture output.

这样,您只需检查返回码而无需捕获输出。

回答by SomeGuyOnAComputer

I was having some issues with this where every time I ran my program, it would change the output. e.g. If I was looking for /bin/bash, it would sometimes return that it was found and other times it would return that it was missing.

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

I got the following code to work consistently for files and folders by preceding what I expected with \r\n

通过在我期望的之前,我得到了以下代码以一致地为文件和文件夹工作 \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"] )

or

或者

# 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 )

Hope this helps you.

希望这对你有帮助。

Edit: Also noticed that when ssh'ing into Windows (cygwin) and trying to see if a file exists, the file must be quoted. On Linux, this is optional. So the %sin host.sendlinewas changed to %r.

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

回答by eric.frederich

I don't have any pexpect experience but looking at their web page it looks like you can call the expect method with multiple values and it returns the index of the one that it matches (this is based purely on me just looking at this example).

我没有任何 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

Actually, you're already using that functionality at the top.

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

So you want to catch whether the file exists or not?...

所以你想捕捉文件是否存在?...

Try this...

尝试这个...

        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'))]

回答by Johan

When you as user type something in ssh, the shell will echo the characters back. That is happening now as well.

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

So, doing:

所以,这样做:

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

Will result in an input of:

将导致输入:

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

Doing:

正在做:

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

Will then always result in i==0, because "File exists" is present in the first line that is received back.

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

An alternative where the original send line, does not have the expected sentence:

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

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

Or more like the original:

或者更像原版:

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

回答by chrissygormley

I have worked the solution that will do me. The code is below:

我已经找到了对我有用的解决方案。代码如下:

def VersionID(): 

    ssh_newkey = 'Are you sure you want to continue connecting' 
    # my ssh command line 
    p=pexpect.spawn('ssh [email protected]') 

    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'])

This extracts the value from 'p' in a string format. I then split the string up to get the string 'File Exists' into a list and compare it to the response I am looking for. If the File does not exists the test will fail.

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

Thanks for all the help.

感谢所有的帮助。