如何从 pexpect.spawn() 收集所有输出
How do I collect ALL output from pexpect.spawn()
目前 c.read() 函数仅 returns 来自我正在调用的程序输出的值,不收集在交互部分发生的事情。 (即:等待用户名和密码)。由于该部分可能会发生错误,因此我需要在调用 cmd 后收集所有输出。
使用 运行 命令可以正常工作。我正在尝试转换为使用 expect.spawn(),因为它看起来非常接近 expect 的 ssh 版本。当前 运行() 方法在本地工作时工作正常。我找不到可以 return 整个输出的 getOutput() 类型函数。
import pexpect
class Expect( ):
def Do( self, cmd, program: list = [], timeout: int = 20 ):
# result = run( cmd, events=program, timeout=timeout).decode()
result = ''
c = pexpect.spawn( cmd, encoding='utf-8', timeout=timeout )
for curItem in program:
# print( 'wait: ' + curItem[0] + ' resp: ' + curItem[1])
c.expect( curItem[0] )
c.sendline( curItem[1] )
# result += c.read()
result += c.read()
print ( 'res: ' + str(result) )
return result
cmd = 'fmsadmin list files -s'
prog = [('username \(.+\):', 'yourUN\n'), ('password:', 'yourPW\n')]
res = Expect().Do( cmd, prog ) # Returns everything
# use results to verify functionality
结果
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
当我期待
username (yourUN):yourUN
password:
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
更新
我在 c.sendline( curItem[1] ) 下面添加了结果 += c.before + c.after 现在 returns:
c.sendline(curItem[1])
username (yourUN): yourUN
password:
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
遗憾的是还有两个问题。 1 输出中还有其他值,例如 returns,如果我提供无效密码,我会在没有应用 returned 值的情况下返回调试详细信息。我得到:
before (last 100 chars): '\r\n/usr/local/bin/fmsadmin: Permission denied, please try again.\r\nusername (yourUN):'
after: <class 'pexpect.exceptions.TIMEOUT'>
match: None
match_index: None
etc
所以简而言之,我正在从 CLI 中寻找完整的 returned 值,就像我手动完成 returned 一样。这就是 运行() 的作用。
Pexpect,就像原来的 TCL Expect 一样,要获得会话输入和输出的正确部分有点棘手。挑战在于格式化您的搜索模式以匹配它应该匹配的内容,并且仅此匹配。要让它正常工作,您所要做的就是用 before
、after
和 match
属性解析 returned object。
也就是说,Pexpect 获取终端显示的所有内容,包括命令和输出。幸运的是,密码没有显示,不幸的是,Pexpect 看不到它们。
from pexpect import spawn, EOF # Better import only needed methods
process = spawn('bash', encoding='utf-8')
process.expect('$') # Expects terminal prompt
process.sendline('read -p "username: " var')
process.expect('\nusername: ') # Gets command, newline and username prompt
process.sendline('me')
process.expect('[^\n]*\n.*$') # Gets typed string, newlind and terminal prompt
print(process.match.group(0)) # Prints whole string matched
me # User typed
me@myhost ~ $ # Terminal prompt
process.sendline('read -sp "password: " var') # Note the '-s' for 'silent'
process.expect('\npassword: ')
process.sendline('my_passwd')
process.expect('.*$') # Trying to match a newline just doesn't work
print(process.match.group(0))
me@myhost ~ $ # Only terminal prompt
process.sendline('exit')
process.expect(EOF)
所以你应该知道你想解决什么样的问题。你为什么要绝对收集所有发送和返回的东西,包括密码?
顺便说一句,您可能已经知道代码中纯密码的问题。我的推荐:getpass
:
from getpass import getpass
password = getpass()
<Then use the password>
顺便说一句,为了以防万一,docs 左右。
好的,我明白了。不太期望,但它是有道理的。几个变化:
- 在 for 循环末尾添加结果 += c.before + c.after。这捕获
来自帐户和密码的输出以及来自 CLI 的任何错误
申请。
- 将 spawn、expect、send 放入 try accept 块中
- Move result += c.read() inside Try before Except (quiet the
例外)
- 异常期间终于调用result += c.buffer
我可能会在下一个版本中删除本地部分(一旦我弄清楚远程案例)
from pexpect import *
class Expect( ):
def Do( self, cmd, program: list = [], timeout: int = 20 ):
local = False
result = ''
if local:
result = runu( cmd, events=program, timeout=timeout )
else:
c = ''
try:
c = spawnu( cmd, timeout=timeout )
for curItem in program:
c.expect( curItem[0] )
c.sendline( curItem[1] )
result += c.before + c.after
result += c.read()
except:
result += c.buffer
return result
cmd = 'fmsadmin list files -s'
prog = [('username \(.+\):', 'yourUN\n'), ('password:', 'yourPW\n')]
res = Expect().Do( cmd, prog, 5 )
print ( '-' * 50 + '\n' + str(res))
目前 c.read() 函数仅 returns 来自我正在调用的程序输出的值,不收集在交互部分发生的事情。 (即:等待用户名和密码)。由于该部分可能会发生错误,因此我需要在调用 cmd 后收集所有输出。
使用 运行 命令可以正常工作。我正在尝试转换为使用 expect.spawn(),因为它看起来非常接近 expect 的 ssh 版本。当前 运行() 方法在本地工作时工作正常。我找不到可以 return 整个输出的 getOutput() 类型函数。
import pexpect
class Expect( ):
def Do( self, cmd, program: list = [], timeout: int = 20 ):
# result = run( cmd, events=program, timeout=timeout).decode()
result = ''
c = pexpect.spawn( cmd, encoding='utf-8', timeout=timeout )
for curItem in program:
# print( 'wait: ' + curItem[0] + ' resp: ' + curItem[1])
c.expect( curItem[0] )
c.sendline( curItem[1] )
# result += c.read()
result += c.read()
print ( 'res: ' + str(result) )
return result
cmd = 'fmsadmin list files -s'
prog = [('username \(.+\):', 'yourUN\n'), ('password:', 'yourPW\n')]
res = Expect().Do( cmd, prog ) # Returns everything
# use results to verify functionality
结果
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
当我期待
username (yourUN):yourUN
password:
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
更新
我在 c.sendline( curItem[1] ) 下面添加了结果 += c.before + c.after 现在 returns: c.sendline(curItem[1])
username (yourUN): yourUN
password:
ID File Clients Size Status Enabled Extended Privileges Encrypted
1 FMServer_Sample.fmp12 0 905216 Normal fmapp fmxml fmphp fmwebdirect No
遗憾的是还有两个问题。 1 输出中还有其他值,例如 returns,如果我提供无效密码,我会在没有应用 returned 值的情况下返回调试详细信息。我得到:
before (last 100 chars): '\r\n/usr/local/bin/fmsadmin: Permission denied, please try again.\r\nusername (yourUN):'
after: <class 'pexpect.exceptions.TIMEOUT'>
match: None
match_index: None
etc
所以简而言之,我正在从 CLI 中寻找完整的 returned 值,就像我手动完成 returned 一样。这就是 运行() 的作用。
Pexpect,就像原来的 TCL Expect 一样,要获得会话输入和输出的正确部分有点棘手。挑战在于格式化您的搜索模式以匹配它应该匹配的内容,并且仅此匹配。要让它正常工作,您所要做的就是用 before
、after
和 match
属性解析 returned object。
也就是说,Pexpect 获取终端显示的所有内容,包括命令和输出。幸运的是,密码没有显示,不幸的是,Pexpect 看不到它们。
from pexpect import spawn, EOF # Better import only needed methods
process = spawn('bash', encoding='utf-8')
process.expect('$') # Expects terminal prompt
process.sendline('read -p "username: " var')
process.expect('\nusername: ') # Gets command, newline and username prompt
process.sendline('me')
process.expect('[^\n]*\n.*$') # Gets typed string, newlind and terminal prompt
print(process.match.group(0)) # Prints whole string matched
me # User typed
me@myhost ~ $ # Terminal prompt
process.sendline('read -sp "password: " var') # Note the '-s' for 'silent'
process.expect('\npassword: ')
process.sendline('my_passwd')
process.expect('.*$') # Trying to match a newline just doesn't work
print(process.match.group(0))
me@myhost ~ $ # Only terminal prompt
process.sendline('exit')
process.expect(EOF)
所以你应该知道你想解决什么样的问题。你为什么要绝对收集所有发送和返回的东西,包括密码?
顺便说一句,您可能已经知道代码中纯密码的问题。我的推荐:getpass
:
from getpass import getpass
password = getpass()
<Then use the password>
顺便说一句,为了以防万一,docs 左右。
好的,我明白了。不太期望,但它是有道理的。几个变化:
- 在 for 循环末尾添加结果 += c.before + c.after。这捕获 来自帐户和密码的输出以及来自 CLI 的任何错误 申请。
- 将 spawn、expect、send 放入 try accept 块中
- Move result += c.read() inside Try before Except (quiet the 例外)
- 异常期间终于调用result += c.buffer
我可能会在下一个版本中删除本地部分(一旦我弄清楚远程案例)
from pexpect import *
class Expect( ):
def Do( self, cmd, program: list = [], timeout: int = 20 ):
local = False
result = ''
if local:
result = runu( cmd, events=program, timeout=timeout )
else:
c = ''
try:
c = spawnu( cmd, timeout=timeout )
for curItem in program:
c.expect( curItem[0] )
c.sendline( curItem[1] )
result += c.before + c.after
result += c.read()
except:
result += c.buffer
return result
cmd = 'fmsadmin list files -s'
prog = [('username \(.+\):', 'yourUN\n'), ('password:', 'yourPW\n')]
res = Expect().Do( cmd, prog, 5 )
print ( '-' * 50 + '\n' + str(res))