如何设置 pexpect ssh 会话的列宽?

How do I set the column width of a pexpect ssh session?

我正在编写一个简单的 python 脚本来通过 SSH 连接到 SAN,运行 一组命令。最终,每个命令都将连同时间戳记录到单独的日志中,然后退出。这是因为我们正在连接的设备不支持证书 ssh 连接,并且在其当前固件版本上没有合适的日志记录功能。

我似乎 运行 遇到的问题是创建的 SSH 会话似乎限制为 78 个字符宽。每个命令生成的结果要宽得多——155 个字符。这引起了一堆时髦。

首先,当前状态下的结果更难解析。其次,由于缓冲区明显较小,最终的卷命令将无法正确执行,因为预期启动的 SSH 会话实际上被提示为 "press any key to continue".

如何更改预期会话的列宽?

这是当前代码(可以使用但不完整):

#!/usr/bin/python

import pexpect
import os

PASS='mypassword'
HOST='1.2.3.4'
LOGIN_COMMAND='ssh manage@'+HOST
CTL_COMMAND='show controller-statistics'
VDISK_COMMAND='show vdisk-statistics'
VOL_COMMAND='show volume-statistics'

VDISK_LOG='vdisk.log'
VOLUME_LOG='volume.log'
CONTROLLER_LOG='volume.log'

DATE=os.system('date +%Y%m%d%H%M%S')

child=pexpect.spawn(LOGIN_COMMAND)
child.setecho(True)
child.logfile = open('FetchSan.log','w+')
child.expect('Password: ')
child.sendline(PASS)
child.expect('# ')
child.sendline(CTL_COMMAND)
print child.before
child.expect('# ')
child.sendline(VDISK_COMMAND)
print child.before
child.expect('# ')
print "Sending "+VOL_COMMAND
child.sendline(VOL_COMMAND)
print child.before
child.expect('# ')
child.sendline('exit')
child.expect(pexpect.EOF)
print child.before

预期输出:

# show controller-statistics
Durable ID     CPU Load   Power On Time (Secs)   Bytes per second   IOPS             Number of Reads  Number of Writes Data Read        Data Written     
---------------------------------------------------------------------------------------------------------------------------------------------------------
controller_A   0          45963169               1573.3KB           67               386769785        514179976        6687.8GB         5750.6GB
controller_B   20         45963088               4627.4KB           421              3208370173       587661282        63.9TB           5211.2GB
---------------------------------------------------------------------------------------------------------------------------------------------------------
Success: Command completed successfully.

# show vdisk-statistics     
Name   Serial Number                    Bytes per second   IOPS             Number of Reads  Number of Writes Data Read        Data Written     
------------------------------------------------------------------------------------------------------------------------------------------------
CRS    00c0ff13349e000006d5c44f00000000 0B                 0                45861            26756            3233.0MB         106.2MB
DATA   00c0ff1311f300006dd7c44f00000000 2282.4KB           164              23229435         76509765         5506.7GB         1605.3GB
DATA1  00c0ff1311f3000087d8c44f00000000 2286.5KB           167              23490851         78314374         5519.0GB         1603.8GB
DATA2  00c0ff1311f30000c2f8ce5700000000 0B                 0                26               4                1446.9KB         65.5KB
FRA    00c0ff13349e000001d8c44f00000000 654.8KB            5                3049980          15317236         1187.3GB         1942.1GB
FRA1   00c0ff13349e000007d9c44f00000000 778.7KB            6                3016569          15234734         1179.3GB         1940.4GB
------------------------------------------------------------------------------------------------------------------------------------------------
Success: Command completed successfully.

# show volume-statistics    
Name        Serial Number                    Bytes per second   IOPS             Number of Reads  Number of Writes Data Read        Data Written     
-----------------------------------------------------------------------------------------------------------------------------------------------------
CRS_v001    00c0ff13349e0000fdd6c44f01000000 14.8KB             5                239611146        107147564        1321.1GB         110.5GB          
DATA1_v001  00c0ff1311f30000d0d8c44f01000000 2402.8KB           218              1701488316       336678620        33.9TB           3184.6GB         
DATA2_v001  00c0ff1311f3000040f9ce5701000000 0B                 0                921              15               2273.7KB         2114.0KB         
DATA_v001   00c0ff1311f30000bdd7c44f01000000 2303.4KB           209              1506883611       250984824        30.0TB           2026.6GB         
FRA1_v001   00c0ff13349e00001ed9c44f01000000 709.1KB            28               25123082         161710495        1891.0GB         2230.0GB         
FRA_v001    00c0ff13349e00001fd8c44f01000000 793.0KB            34               122052720        245322281        3475.7GB         3410.0GB         
-----------------------------------------------------------------------------------------------------------------------------------------------------
Success: Command completed successfully.

打印到终端的输出(如前所述,第三条命令不会在其当前状态下执行):

show controller-statistics
Durable ID     CPU Load   Power On Time (Secs)   Bytes per second   
  IOPS             Number of Reads  Number of Writes Data Read        
  Data Written     
----------------------------------------------------------------------
controller_A   3          45962495               3803.1KB           
  73               386765821        514137947        6687.8GB         
  5748.9GB
controller_B   20         45962413               5000.7KB           
  415              3208317860       587434274        63.9TB           
  5208.8GB
----------------------------------------------------------------------
Success: Command completed successfully.


Sending show volume-statistics
show vdisk-statistics
Name   Serial Number                    Bytes per second   IOPS             
  Number of Reads  Number of Writes Data Read        Data Written     
----------------------------------------------------------------------------
CRS    00c0ff13349e000006d5c44f00000000 0B                 0                
  45861            26756            3233.0MB         106.2MB
DATA   00c0ff1311f300006dd7c44f00000000 2187.2KB           152              
  23220764         76411017         5506.3GB         1604.1GB
DATA1  00c0ff1311f3000087d8c44f00000000 2295.2KB           154              
  23481442         78215540         5518.5GB         1602.6GB
DATA2  00c0ff1311f30000c2f8ce5700000000 0B                 0                
  26               4                1446.9KB         65.5KB
FRA    00c0ff13349e000001d8c44f00000000 1829.3KB           14               
  3049951          15310681         1187.3GB         1941.2GB
FRA1   00c0ff13349e000007d9c44f00000000 1872.8KB           14               
  3016521          15228157         1179.3GB         1939.5GB
----------------------------------------------------------------------------
Success: Command completed successfully.
Traceback (most recent call last):
  File "./fetchSAN.py", line 34, in <module>
    child.expect('# ')
  File "/Library/Python/2.7/site-packages/pexpect-4.2.1-py2.7.egg/pexpect/spawnbase.py", line 321, in expect
    timeout, searchwindowsize, async)
  File "/Library/Python/2.7/site-packages/pexpect-4.2.1-py2.7.egg/pexpect/spawnbase.py", line 345, in expect_list
    return exp.expect_loop(timeout)
  File "/Library/Python/2.7/site-packages/pexpect-4.2.1-py2.7.egg/pexpect/expect.py", line 107, in expect_loop
    return self.timeout(e)
  File "/Library/Python/2.7/site-packages/pexpect-4.2.1-py2.7.egg/pexpect/expect.py", line 70, in timeout
    raise TIMEOUT(msg)
pexpect.exceptions.TIMEOUT: Timeout exceeded.
<pexpect.pty_spawn.spawn object at 0x105333910>
command: /usr/bin/ssh
args: ['/usr/bin/ssh', 'manage@10.254.27.49']
buffer (last 100 chars): '-------------------------------------------------------------\r\nPress any key to continue (Q to quit)'
before (last 100 chars): '-------------------------------------------------------------\r\nPress any key to continue (Q to quit)'
after: <class 'pexpect.exceptions.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 19519
child_fd: 5
closed: False
timeout: 30
delimiter: <class 'pexpect.exceptions.EOF'>
logfile: <open file 'FetchSan.log', mode 'w+' at 0x1053321e0>
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
searcher: searcher_re:
    0: re.compile("# ")

这是日志中捕获的内容:

Password: mypassword


HP StorageWorks MSA Storage P2000 G3 FC
System Name: Uninitialized Name
System Location:Uninitialized Location
Version:TS230P008
# show controller-statistics
show controller-statistics
Durable ID     CPU Load   Power On Time (Secs)   Bytes per second   
  IOPS             Number of Reads  Number of Writes Data Read        
  Data Written     
----------------------------------------------------------------------
controller_A   3          45962495               3803.1KB           
  73               386765821        514137947        6687.8GB         
  5748.9GB
controller_B   20         45962413               5000.7KB           
  415              3208317860       587434274        63.9TB           
  5208.8GB
----------------------------------------------------------------------
Success: Command completed successfully.

# show vdisk-statistics
show vdisk-statistics
Name   Serial Number                    Bytes per second   IOPS             
  Number of Reads  Number of Writes Data Read        Data Written     
----------------------------------------------------------------------------
CRS    00c0ff13349e000006d5c44f00000000 0B                 0                
  45861            26756            3233.0MB         106.2MB
DATA   00c0ff1311f300006dd7c44f00000000 2187.2KB           152              
  23220764         76411017         5506.3GB         1604.1GB
DATA1  00c0ff1311f3000087d8c44f00000000 2295.2KB           154              
  23481442         78215540         5518.5GB         1602.6GB
DATA2  00c0ff1311f30000c2f8ce5700000000 0B                 0                
  26               4                1446.9KB         65.5KB
FRA    00c0ff13349e000001d8c44f00000000 1829.3KB           14               
  3049951          15310681         1187.3GB         1941.2GB
FRA1   00c0ff13349e000007d9c44f00000000 1872.8KB           14               
  3016521          15228157         1179.3GB         1939.5GB
----------------------------------------------------------------------------
Success: Command completed successfully.

# show volume-statistics
show volume-statistics
Name        Serial Number                    Bytes per second   
  IOPS             Number of Reads  Number of Writes Data Read        
  Data Written     
----------------------------------------------------------------------
CRS_v001    00c0ff13349e0000fdd6c44f01000000 11.7KB             
  5                239609039        107145979        1321.0GB         
  110.5GB          
DATA1_v001  00c0ff1311f30000d0d8c44f01000000 2604.5KB           
  209              1701459941       336563041        33.9TB           
  3183.3GB         
DATA2_v001  00c0ff1311f3000040f9ce5701000000 0B                 
  0                921              15               2273.7KB         
  2114.0KB         
DATA_v001   00c0ff1311f30000bdd7c44f01000000 2382.8KB           
  194              1506859273       250871273        30.0TB           
  2025.4GB         
FRA1_v001   00c0ff13349e00001ed9c44f01000000 1923.5KB           
  31               25123006         161690520        1891.0GB         
  2229.1GB         
FRA_v001    00c0ff13349e00001fd8c44f01000000 2008.5KB           
  37               122050872        245301514        3475.7GB         
  3409.1GB         
----------------------------------------------------------------------
Press any key to continue (Q to quit)% 

作为起点:According to the manual,SAN 有一个禁用寻呼机的命令。请参阅 set cli-parameters pager off 的文档。执行该命令可能就足够了。它也可能有一个命令来设置它用于格式化输出的终端行和列,尽管我找不到一个。

回答您的问题:当 ssh 客户端连接到服务器并请求交互式会话时,它可以选择为会话的服务器端请求 PTY(伪 tty)。当它这样做时,它会通知服务器服务器应该用于 TTY 的行、列和终端类型。您的 SAN 可能会接受 PTY 请求并使用行和列值来格式化其输出。或者它可能不会。

ssh 客户端从 TTY 获取 PTY 请求的行和列作为其标准输入。这是 pexpect 用来与 ssh 通信的 PTY。 this question discusses how to set the terminal size for a pexpect session. Ssh doesn't honor the LINES or COLUMNS environment variables as far as I can tell, so I doubt that would work. However, calling child.setwinsize() 生成 ssh 后应该可以工作:

child = pexpect.spawn(cmd)
child.setwinsize(400,400)

如果您对此有困难,您可以尝试通过在 ssh 之前在本地调用 stty 来设置终端大小:

child=pexpect.spawn('stty rows x cols y; ssh user@host')

最后,您需要确保 ssh 确实为会话请求了 PTY。它在某些情况下默认执行此操作,这应该包括您的方式 运行。但是它有一个命令行选项 -tt 来强制它分配一个 PTY。您可以将该选项添加到 ssh 命令行以确保:

child=pexpect.spawn('ssh -tt user@host')
or
child=pexpect.spawn('stty rows x cols y; ssh -tt user@host')