shell里使用expect不怎么好用,语法太丑陋,现来试试python中的pexpect。
其实对于登录ssh这种交互操作,python有专门的pxssh:
import pxssh
但是help中的实验代码一直报错,网上的解决方案是修改pxssh中的源码, 太麻烦,决定放弃pxssh,学习使用更通用的pexpect,其实pxssh也就是基于pexpect实现的。报错信息粘贴如下:
Traceback (most recent call last):
File "test_pxssh.py", line 10, in <module>
s.login (hostname, username, password)
File "/usr/lib/python2.7/dist-packages/pxssh.py", line 243, in login
if not self.synch_original_prompt():
File "/usr/lib/python2.7/dist-packages/pxssh.py", line 134, in synch_original_prompt
self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 824, in read_nonblocking
raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
pexpect.TIMEOUT: Timeout exceeded in read_nonblocking().
举个scp的例子:
import pexpect
child = pexpect.spawn('scp ip.html xxx.xxx.xxx.xxx:~/')
child.expect(':', timeout=1)
child.sendline('xxxxx')
child.isalive()
child.expect(pexpect.EOF)
child.close()
特别注意,pexpect会不解析如下一些符号:
| > *
如果你想使用它们,你应该开启一个bash终端,像这面这样:
child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"')
child.expect(pexpect.EOF)
又特别注意,child.expect的第一个参数是匹配参数,会被编译成一个正则对象,所以可以是字符串,也可以是已经编译好的正则对象, 而且可以是一个list,用于逐个尝试,还可以是一个特殊代号,如pexpect.EOF, pexpect.TIMEOUT等。它返回值为正则对象的索引值。 所以你应该这么写:
index = child.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
if index == 0:
do_something()
elif index == 1:
do_something_else()
elif index == 2:
do_some_other_thing()
elif index == 3:
do_something_completely_different()
而不应该这么写,尽管也是work的:
try:
index = child.expect (['good', 'bad'])
if index == 0:
do_something()
elif index == 1:
do_something_else()
except EOF:
do_some_other_thing()
except TIMEOUT:
do_something_completely_different()
当然有种匹配所有字符的懒惰写法:
index = child.except([r'.*', pexpect.EOF, pexpect.TIMEOUT], timeout=1)
child.before是匹配位置之前的字符串,child.after是匹配的字符串,child.buffer是匹配位置之后的字符串。
还可以通过如下方法,来接管交互,人工介入:
child.interact()
使用如下模块来获取输入可以像获取密码一样,不显示用户的输入内容:
import getpass
res = getpass.getpass()