【问题标题】:Mixing Expect and BASH混合期望和 BASH
【发布时间】:2012-02-16 21:34:00
【问题描述】:

我已经编写了一个小的 Expect 脚本来登录 Cisco 设备;登录后,我想重复运行命令并grep 输出。

#!/usr/bin/expect

send_user "Device name: "
expect_user -re "(.*)\n"
set host $expect_out(1,string)

send_user "Username: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)

stty -echo
send_user -- "Password: "
expect_user -re "(.*)\n"
set pass $expect_out(1,string)
stty echo

send_user "show int "
expect_user  -re "(.*)\n"
set intf $expect_out(1,string)
send_user "\n"

spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect ">"

此时我们已经登录到设备,我想重复执行命令“show int xxx”并grep特定行的输出。 grep 不在 Expect 中,也没有像 sleep 这样的命令,所以我可以循环执行 show int 命令,grepping 在我的特定行之外。我怎样才能像这样混合 Expect 和 Bash?

更新:我现在已经完成了相当多的脚本,一旦我克服了最后一个障碍,我会发布完整的脚本。一行set bytesnow [exec grep "packets input" \< showint | cut -d \ -f 9] 抛出错误;

child process exited abnormally
   while executing
"exec grep "packets input" < \showint | cut -d \  -f 9"

但它在我编写的测试脚本中运行良好。文件 ./showint 在那里,在命令行上运行该命令可以正常工作吗?我不知道出了什么问题?

更新:更多调查 (http://wiki.tcl.tk/8489) 显示 grep 以状态码 1 退出,这意味着没有找到模式匹配,把该命令在命令行中可以正常工作吗?即使使用 /full/path/to/showint。

END:我意识到自己曾经是个傻瓜,从而纠正了我的错误,答案如下。感谢大家的帮助:D

【问题讨论】:

  • 哈!错字,更正,欢呼;)
  • 看来您正在router#sh int &lt;int&gt; | i packets input 字段中查找字段 9,并以空格作为分隔符。我的输出中只看到 8 个字段。你能告诉我们你想要完成什么吗? 798518177 packets input, 60933723489 bytes, 0 no buffer
  • 我使用了“-f 9”,因为交换机/路由器上的那一行输出在开头有几个空格,用于缩进。我正在尝试按照该输出行的字节值工作。在底部查看我的答案。谢谢:)

标签: bash automation expect cisco


【解决方案1】:

这就是我要做的

log_user 0
while(1) {
  send -- "sh int $intf | i packets input\r"
  set timeout 5
  expect {
    -re "^ +(\d+) packets" { send_user -- "$expect_out(1,string)" }
    timeout { send_user "broke?\n" }
  }
}

这将为您提供输入的数据包数量。

【讨论】:

  • 虽然这是一个我非常喜欢的非常酷的想法,但我的脚本的目的(我之前没有解释,所以这是我的错)是获取接口的当前吞吐量。有关完整脚本,请参阅下面的答案。谢谢你的好主意:D
【解决方案2】:

这是我的第一个 Expect 脚本,其目的是提供接口的实时(几乎 1 秒!)吞吐量。下面的例子给出了一个接口输入速度,因为我们grep 用于包含“数据包输入”的行。将其更改为“数据包输出”以获得该接口的实时输出速率。

#!/usr/bin/expect

# Long delay for those tricky hostnames

set timeout 60

# Prompt user for device name/IP, username, password, 
# and interface to query (gi0/2)

send_user "Device name: "
expect_user -re "(.*)\n"
set host $expect_out(1,string)

send_user "Username: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)

stty -echo
send_user "Password: "
expect_user -re "(.*)\n"
set pass $expect_out(1,string)
send_user "\n"
stty echo

send_user "show int "
expect_user  -re "(.*)\n"
set intf $expect_out(1,string)
send_user "\n"

spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect ">"

set byteslast 0
set bytesnow 0

log_user 0

# Enter a continuous loop grabbing the number of bytes that
# have passed through an interface, each second.
# The different in this number each cycle, is essentially
# how much traffic this interface is pushing.

while { true } {
  send "show int $intf\r"
  expect ">"

  set showint [open "showint" "w"]
  puts $showint $expect_out(buffer)
  close $showint

  set bytesnow [exec grep "packets input" \< showint | cut -d \  -f 9]

  if { $bytesnow > $byteslast } {
    set diff [expr $bytesnow - $byteslast]
    set bps [exec expr "$diff" \* 8]
    set kbps [exec expr "$bps" \/ 1000]
  } elseif { $bytesnow < $byteslast } {
    set diff [expr $byteslast - $bytesnow]
    set bps [exec expr "$diff" \* 8]
    set kbps [exec expr "$bps" \/ 1000]
  } elseif { $bytesnow == $byteslast } {
    set kbps 0
  }

  set byteslast $bytesnow
  puts "$kbps Kbps\r"

  sleep 1
}

由于这是我的第一个 Expect 脚本,我毫不怀疑它可以更高效、更清晰地编写(我发现总是如此),所以如果有人对此有任何指示,我会全力以赴! :)

我的exec grep 命令的问题原来是在此之前,我打开的文件“showint”,我没有关闭,我试图访问另一个文件;小学生的错误!

【讨论】:

  • 如果您想保留所有内容,可以使用 TCL 命令regexp 进行 grep。我相信你的命令是[regexp { \(\d+\) bytes} $showint bytesnow]。此外,当您可以使用内置 TCL expr 命令时,您的 [exec expr 行不必要地调用 shell 命令 expr。只需摆脱这些命令中的exec
  • 另外,更优雅的长期解决方案是使用 snmp。你签出MRTGNMIS 了吗?
  • 我有 SNMP 用于整体监控,但我需要这个脚本来进行故障排除,当我想立即查看接口流量时,而不是在轮询器运行的五分钟内查看 :)
猜你喜欢
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2016-02-28
  • 2020-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多