Expect脚本执行文件命令丢失问题排查与优化建议
问题描述
编写了Expect脚本用于逐行发送文件中的命令到终端,但执行后仅发送了2条release-subscriber-imsi命令(共4条),其余命令未执行。相关信息如下:
脚本代码
set saddress [lrange $argv 0 0] spawn ssh Rd@$saddress expect "password:" send "AAAA\r" #expect "#" #send "terminal length 0\r" set namafile [lindex $argv 1] set f [ open "$namafile" ] set commands [ split [read $f] "\n"] close $f foreach cmd $commands { expect { "#" { send -- "$cmd\r" } "No]:" { send -- "Y\r" } } #sleep 2 } expect "#" send "logout\r"
待执行命令文件内容
== conf t xgw pgw release-subscriber-imsi 510092008527215 release-subscriber-imsi 510092008497549 release-subscriber-imsi 510092008497291 release-subscriber-imsi 510092008479295 end write
执行命令
/usr/bin/expect kickuserxGW30.txt 172.31.201.98 userbandunginxgw30.txt > /resultkick/xGW30.txt &
结果日志
30#conf t Enter configuration commands, one per line. End with CTRL/Z. 30(config)#xgw 30(config-xgw)#pgw 30(config-xgw-pgw)#release-subscriber-imsi 510092008527215 Release online subscriber according to IMSI information. Are you sure to continue? [Yes/No]:Y %Code 170002: Error, no user found! SPJKTZ030(config-xgw-pgw)#release-subscriber-imsi 510092008497291 Release online subscriber according to IMSI information. Are you sure to continue? [Yes/No]:Y %Code 170002: Error, no user found! 30(config-xgw-pgw)#end 30#write Write DB OK! Building configuration... .[OK]. 30#
问题原因分析
- 命令匹配逻辑漏洞:循环内的
expect块同时监听#和No]:,当发送Y确认后,设备返回错误信息并回到#提示符,但脚本没有等待这个提示符就进入下一次循环,导致后续命令被错误地发送到未就绪的上下文,直接被设备输出覆盖或丢失。 - 无效命令行干扰:命令文件第一行的
==是无效命令,执行后会产生错误输出,干扰脚本对正常提示符的匹配节奏。 - 空命令行问题:用
split分割文件时,若文件存在换行空行,会生成空命令,发送空命令会导致设备重复输出提示符,打乱脚本的匹配逻辑。 - 缺少必要的等待同步:没有在发送确认指令后强制等待回到
#提示符,导致脚本和设备的执行节奏不同步。
优化建议
1. 修复命令执行的同步逻辑
调整循环内的expect处理,确保每次发送命令(包括确认指令)后,必须等待回到#提示符再进行下一步:
foreach cmd $commands { # 跳过空行和无效的==行 set trimmed_cmd [string trim $cmd] if {$trimmed_cmd eq "" || $trimmed_cmd eq "=="} { continue } # 等待提示符就绪再发命令 expect "#" send -- "$trimmed_cmd\r" # 处理可能的确认提示 expect { "No]:" { send -- "Y\r" expect "#" ;# 强制等待回到提示符 } "#" { # 无需确认的命令直接进入下一次循环 } } }
2. 提前过滤无效命令行
读取命令文件时直接清理空行和无效行,避免无效命令干扰:
set f [ open "$namafile" ] set commands [ split [read $f] "\n"] close $f # 清理命令列表 set clean_cmds [list] foreach cmd $commands { set trimmed [string trim $cmd] if {$trimmed ne "" && $trimmed ne "=="} { lappend clean_cmds $trimmed } } set commands $clean_cmds
3. 启用超时与分页禁用
- 添加超时配置防止脚本挂起:在脚本开头加入
set timeout 10(单位:秒) - 取消注释
terminal length 0相关代码,禁用设备分页输出,避免分页提示干扰匹配:
expect "#" send "terminal length 0\r" expect "#"
内容的提问来源于stack exchange,提问作者Wolverine adamantium
相关产品推荐
相关产品推荐

