问题
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:
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()
Thanks for any help.
回答1:
If the server accepts sftp sessions, I wouldn't bother with pexpect, but instead use the paramiko SSH2 module for Python:
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 SFTPClient connection to the server, on which you can use stat() to check for the existance of files and directories.
sftp.stat will raise an IOError ('No such file') when the file doesn't exist.
If the server doesn't support sftp, this would work:
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.
回答2:
Why not take advantage of the fact that the return code of the command is passed back over 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.
回答3:
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.
I got the following code to work consistently for files and folders by preceding what I expected with \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 %s
in host.sendline
was changed to %r
.
回答4:
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).
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'))]
回答5:
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 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'])
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.
Thanks for all the help.
回答6:
When you as user type something in ssh, the shell will echo the characters back. That is happening now as well.
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.
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'])
来源:https://stackoverflow.com/questions/2192442/verify-a-file-exists-over-ssh