EXPECT SCRIPT:procedure 在实际代码之前是 运行
EXPECT SCRIPT:procedure being ran before actual code
我正在创建一个 expect 脚本,让我在管理 cisco 设备时使用宏。
完成所有连接后,我的脚本等待“#”,因此我知道用户已准备好输入。如果我在交互之后定义我的过程,脚本工作正常,但显然它还没有被声明,所以脚本失败。如果我在交互之前定义它,我会超时,就像它实际上是 "expecting"
为什么这个过程 "run" 甚至没有被调用?
proc portSec {port} {
send "show port interface $int\r"
expect {
-nocase -re "(invalid)|(ambig}" {
puts "\nInvalid Interface\n"
return
}
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
}
}
~~~~expect "#" ~~~~~~
send "show port address \| i $mac\r"
expect "#"
}
interact {
"!p" {
send_user "\nWelcome to macro mode!\nWhich interface would you like to clear port security?: "
stty echo
expect_user -re "(.*)\r" {
set port $expect_out(1,string)
}
stty -echo
portSec $port
send "\r"
}
}
这里是调试
expect: does " \r\nYour password will expire in 1 week, 5 days, 3 hours,
44 minutes and 56 seconds
\r\r\n\r\nHOSTNAME line 1 \r\n\r\nHOSTNAME#" (spawn_id exp4)
match glob pattern "#"? yes
expect: set expect_out(0,string) "#"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) " \r\nYour password will expire in 1 week,
5 days, 3 hours, 44 minutes and 56 seconds\r\r\n\r\nHOSTNAME line 1
n\r\nHOSTNAME#"
expect: does "" (spawn_id exp4) match glob pattern "#"? no
expect: timed out
can't read "mac": no such variable
while executing
"send "show port address \| i $mac\r""
(file "./ios.exp" line 78)
单步执行调试器,我在预期的行中添加了“~~~”
哦!!!可怜的我。我怎么漏了这个错误!!! :-D
撞了半天脑袋,发现你在expect语句中误用了大括号
-nocase -re "(invalid)|(ambig}" {
将其改为括号,解决了这个问题。 :-)
proc portSec {port} {
send "show port interface $int\r"
expect {
-nocase -re "(invalid)|(ambig)" {
puts "\nInvalid Interface\n"
return
}
-nocase -re {\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]} {
set mac $expect_out(1,string)
}
}
expect "#";#
send "show port address \| i $mac\r"
expect "#"
}
现在一切都说得通了。但是,为什么 Expect
没有抛出任何错误?那么为什么它必须接受大括号的其余部分作为正确的部分呢?
好吧,由于错放了大括号,Expect
假设它关闭了第一个 expect 语句。剩余的代码段是
# two code segments enclosed in braces
# 'Expect' assumes these two as pattern-action pair
# which is why no errors thrown for these blocks.
{
puts "\nInvalid Interface\n"
return
}
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
}
};# This one closes the proc 'portSec'
####### Below code is now in global scope #########3
expect "#"; # Now, wait for '#'
# Send this command now, but wait...
# I don't know about the variable 'mac'
send "show port address \| i $mac\r"
expect "#"
从而将错误消息抛出为 can't read "mac": no such variable
。
最终产品:
#port security clear feature
proc clearPortSec {} {
send_user "\n=====\nWelcome to the Port Security Macro!!!!!\nWhich interface would you like to clear port security?: "
#interact seems to turn of user echoing... turn it back on so the user can make changes
stty echo
expect_user -re "(.*)\r" {
set port $expect_out(1,string)
}
stty -echo
#send ctrl+u to clear the line, and send ctrl+z so we know we are in enable mode
send "52\r"
expect "#"
#verify it is explicitly an access port, if not we don't do the operations to prevent trunks from being shut
send "sho run int $port \| i switchport mode access\r"
expect {
-nocase -re "\r\n\[ \]*switchport mode access\[ \]*\r\n.*#" {
send "\rshow port interface $port\r"
expect {
#grabs offending mac address on this port
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
expect "#"
#finds where switch learned the offending mac
send "show port address \| i $mac\r"
expect {
#case where switch learned mac from another interface
-nocase -re "sticky +(\[^ \]+)" {
set offendport $expect_out(1,string)
puts "\n=====\nMac was found on interface $offendport. Clearing $offendport\n====="
#clear port mac was found on
expect "#"
send "\rconf t\r"; expect "#"
send "interface $offendport\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r;" expect "#"
#switch to original port
send "interface $port\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r"; expect "#"
#end all operation and print status of each port
send "end\r"; expect "#"
send "wr\r"; expect "#"
puts "\n=====\nSleeping a few seconds..\nPrevious port will NOT be shut. Please shut if necessary\n====="
send "show int $offendport status\r"; expect "#"
send "show int $port status\r"; expect "#"
}
#case where switch never learned mac
"#" {
puts "\n=====\nMac is no where else on the switch, clearing existing sticky mac from $port\n====="
send "\rconf t\r"; expect "#"
send "interface $port\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r"; expect "#"
send "end\r"; expect "#"
send "wr\r"; expect "#"
puts "\n=====\nSleeping a few seconds..\n====="
sleep 3
send "show int $port status\r"
}
}
}
}
}
#if we get back '%' - input error, if we get back '#' switchport mode access doesn't exist
-re "\[%#\]" {
puts "\n=====\nInvalid Interface\nThis script ignores all interfaces that don't have \"Switchport mode access\"\n====="
send "\r"
}
}
}
# Don't check keys
spawn ssh -o StrictHostKeyChecking=no $username\@$hostname
expect {
"assword:" {
interact -o -re "\[#>\]" return {
puts "\nLog in Complete"
}
}
timeout {
puts "=====\n$hostname timeout\n====="
exit 1
}
eof {
exit 1
}
}
send "\n"
expect "#"
set timeout -1
interact {
-re "!\[Hh\]" {
puts "\n=====\nMacro list\n=====\nPort Security: !p\n\n"
send "\r"
expect "#"
}
"!p" { clearPortSec }
}
我正在创建一个 expect 脚本,让我在管理 cisco 设备时使用宏。
完成所有连接后,我的脚本等待“#”,因此我知道用户已准备好输入。如果我在交互之后定义我的过程,脚本工作正常,但显然它还没有被声明,所以脚本失败。如果我在交互之前定义它,我会超时,就像它实际上是 "expecting"
为什么这个过程 "run" 甚至没有被调用?
proc portSec {port} {
send "show port interface $int\r"
expect {
-nocase -re "(invalid)|(ambig}" {
puts "\nInvalid Interface\n"
return
}
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
}
}
~~~~expect "#" ~~~~~~
send "show port address \| i $mac\r"
expect "#"
}
interact {
"!p" {
send_user "\nWelcome to macro mode!\nWhich interface would you like to clear port security?: "
stty echo
expect_user -re "(.*)\r" {
set port $expect_out(1,string)
}
stty -echo
portSec $port
send "\r"
}
}
这里是调试
expect: does " \r\nYour password will expire in 1 week, 5 days, 3 hours,
44 minutes and 56 seconds
\r\r\n\r\nHOSTNAME line 1 \r\n\r\nHOSTNAME#" (spawn_id exp4)
match glob pattern "#"? yes
expect: set expect_out(0,string) "#"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) " \r\nYour password will expire in 1 week,
5 days, 3 hours, 44 minutes and 56 seconds\r\r\n\r\nHOSTNAME line 1
n\r\nHOSTNAME#"
expect: does "" (spawn_id exp4) match glob pattern "#"? no
expect: timed out
can't read "mac": no such variable
while executing
"send "show port address \| i $mac\r""
(file "./ios.exp" line 78)
单步执行调试器,我在预期的行中添加了“~~~”
哦!!!可怜的我。我怎么漏了这个错误!!! :-D
撞了半天脑袋,发现你在expect语句中误用了大括号
-nocase -re "(invalid)|(ambig}" {
将其改为括号,解决了这个问题。 :-)
proc portSec {port} {
send "show port interface $int\r"
expect {
-nocase -re "(invalid)|(ambig)" {
puts "\nInvalid Interface\n"
return
}
-nocase -re {\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]} {
set mac $expect_out(1,string)
}
}
expect "#";#
send "show port address \| i $mac\r"
expect "#"
}
现在一切都说得通了。但是,为什么 Expect
没有抛出任何错误?那么为什么它必须接受大括号的其余部分作为正确的部分呢?
好吧,由于错放了大括号,Expect
假设它关闭了第一个 expect 语句。剩余的代码段是
# two code segments enclosed in braces
# 'Expect' assumes these two as pattern-action pair
# which is why no errors thrown for these blocks.
{
puts "\nInvalid Interface\n"
return
}
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
}
};# This one closes the proc 'portSec'
####### Below code is now in global scope #########3
expect "#"; # Now, wait for '#'
# Send this command now, but wait...
# I don't know about the variable 'mac'
send "show port address \| i $mac\r"
expect "#"
从而将错误消息抛出为 can't read "mac": no such variable
。
最终产品:
#port security clear feature
proc clearPortSec {} {
send_user "\n=====\nWelcome to the Port Security Macro!!!!!\nWhich interface would you like to clear port security?: "
#interact seems to turn of user echoing... turn it back on so the user can make changes
stty echo
expect_user -re "(.*)\r" {
set port $expect_out(1,string)
}
stty -echo
#send ctrl+u to clear the line, and send ctrl+z so we know we are in enable mode
send "52\r"
expect "#"
#verify it is explicitly an access port, if not we don't do the operations to prevent trunks from being shut
send "sho run int $port \| i switchport mode access\r"
expect {
-nocase -re "\r\n\[ \]*switchport mode access\[ \]*\r\n.*#" {
send "\rshow port interface $port\r"
expect {
#grabs offending mac address on this port
-nocase -re "(\[0-9\]+.\[^ \]+.\[^ \]+):\[^ \]" {
set mac $expect_out(1,string)
expect "#"
#finds where switch learned the offending mac
send "show port address \| i $mac\r"
expect {
#case where switch learned mac from another interface
-nocase -re "sticky +(\[^ \]+)" {
set offendport $expect_out(1,string)
puts "\n=====\nMac was found on interface $offendport. Clearing $offendport\n====="
#clear port mac was found on
expect "#"
send "\rconf t\r"; expect "#"
send "interface $offendport\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r;" expect "#"
#switch to original port
send "interface $port\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r"; expect "#"
#end all operation and print status of each port
send "end\r"; expect "#"
send "wr\r"; expect "#"
puts "\n=====\nSleeping a few seconds..\nPrevious port will NOT be shut. Please shut if necessary\n====="
send "show int $offendport status\r"; expect "#"
send "show int $port status\r"; expect "#"
}
#case where switch never learned mac
"#" {
puts "\n=====\nMac is no where else on the switch, clearing existing sticky mac from $port\n====="
send "\rconf t\r"; expect "#"
send "interface $port\r"; expect "#"
send "no switchport port-security mac-address sticky\r"; expect "#"
send "switchport port-security mac-address sticky\r"; expect "#"
send "shut\r"; expect "#"
send "no shut\r"; expect "#"
send "end\r"; expect "#"
send "wr\r"; expect "#"
puts "\n=====\nSleeping a few seconds..\n====="
sleep 3
send "show int $port status\r"
}
}
}
}
}
#if we get back '%' - input error, if we get back '#' switchport mode access doesn't exist
-re "\[%#\]" {
puts "\n=====\nInvalid Interface\nThis script ignores all interfaces that don't have \"Switchport mode access\"\n====="
send "\r"
}
}
}
# Don't check keys
spawn ssh -o StrictHostKeyChecking=no $username\@$hostname
expect {
"assword:" {
interact -o -re "\[#>\]" return {
puts "\nLog in Complete"
}
}
timeout {
puts "=====\n$hostname timeout\n====="
exit 1
}
eof {
exit 1
}
}
send "\n"
expect "#"
set timeout -1
interact {
-re "!\[Hh\]" {
puts "\n=====\nMacro list\n=====\nPort Security: !p\n\n"
send "\r"
expect "#"
}
"!p" { clearPortSec }
}