Tcl 如何搜索存储在列表中的多个模式,直到找到所有项目或经过设定的时间

Tcl 如何搜索存储在列表中的多个模式,直到找到所有项目或经过设定的时间,tcl,expect,Tcl,Expect,我正在制作一个简单的expect脚本,它将监视tcpdump的输出,以获取多播地址列表。在expect超时之前,我想知道是否从列表中的每个多播地址接收到数据包 我有一个可行的解决方案,但效率很低,我相信我没有充分利用expect和tcl的强大功能。无论如何,这是我当前的脚本: set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3} send "tcpdump -i ixp1\r" # If tcpdump does not start, unzip

我正在制作一个简单的expect脚本,它将监视tcpdump的输出,以获取多播地址列表。在expect超时之前,我想知道是否从列表中的每个多播地址接收到数据包

我有一个可行的解决方案,但效率很低,我相信我没有充分利用expect和tcl的强大功能。无论如何,这是我当前的脚本:

set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3}

send "tcpdump -i ixp1\r"
# If tcpdump does not start, unzip it and run it again
expect {
  "tcpdump: listening on ixp1" {}
  "sh: tcpdump: not found" {
    send "gunzip /usr/sbin/tcpdump.gz\r"
    expect "# "
    send "tcpdump -i ixp1\r"
    exp_continue
  }
}
# Set timeout to the number of seconds expect will check for ip addresses
set timeout 30
set found [list]
set not_found [list]
foreach ip $multicast_list {
  expect {
    "> $ip" { lappend found "$ip" }
    timeout { lappend not_found "$ip" }
  }
}
set timeout 5
# Send ^c to stop tcpdump
send -- "\003"
expect "# "
因此,正如您所看到的,脚本将一次查找一个ip地址,如果看到该ip,它将把它添加到找到的地址列表中。如果expect超时,它会将地址添加到“未找到”列表并搜索下一个地址

现在回到我的问题:是否有一种方法可以在给定的时间内同时监视所有IP地址的tcpdump。如果要找到地址,我想将其添加到找到的地址列表中,理想情况下不要再期待它(这可能不可能,我不确定)。关键是我需要脚本来并行监视列表中的所有IP。我不能硬编码每个地址,因为它们每次都会不同,我要寻找的地址数量也会不同。我真的需要期待大师的帮助


谢谢大家!

这是一个有趣的问题。最简单的方法可能是运行时生成expect脚本的核心。幸运的是,Tcl在这方面非常擅长。(注意:我假设IP地址都是IPv4地址,并且只包含数字和句点;如果插入的是一般字符串,我就必须更加小心。)


您可能希望
在开始的几次中放入$expbody
,这样您就可以确保它所做的事情是正确的。

这是我完成的脚本。它使用了Donal解决方案中的相同代码,但我添加了一些检查来修复一些未考虑的问题

set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3}
set tcpdump_timeout 10

spawn /bin/bash
expect "] "

# Create the runtime-generated expbody to use later
# Generate the timeout clause as a normal literal
set expbody {
timeout {
    set not_found [array names waiting]
    unset waiting
}
}
foreach ip $multicast_list {
    set waiting($ip) "dummy"
    # Generate the per-ip clause as a multi-line string; beware a few backslashes
    append expbody "\"> $ip\" {
    set currentTime \[clock seconds\]
    if { \$currentTime < \$endTime } {
      if { \[ info exists waiting($ip) \] } {
        lappend found $ip
        unset waiting($ip)
      }
      if {\[array size waiting\]} exp_continue
    }
}\n"
}

# Set expect timeout and create empty lists for tcpdump results
set timeout $tcpdump_timeout
set found [list]
set not_found [list]

# Start tcpdump
send "tcpdump -i ixp1\r"
expect "tcpdump: listening on ixp1"

# Get the time to stop tcpdump
set endTime [ expr [clock seconds] + $tcpdump_timeout ]

# Feed expbody into expect; it's none-the-wiser that it was runtime-generated
expect $expbody
set not_found [array names waiting]
unset waiting
# Send ^c to stop tcpdump
send -- "\003"
expect "# "
set multicast_list{225.0.0.1 225.0.0.2 225.0.0.3}
设置tcpdump_超时10
繁殖/bin/bash
期望“]”
#创建运行时生成的expbody以供以后使用
#将timeout子句作为普通文本生成
集合扩展体{
超时{
未找到集合[array names waiting]
取消等待
}
}
foreach ip$多播\u列表{
设置等待($ip)“虚拟”
#将per ip子句生成为多行字符串;注意一些反斜杠
追加expbody“\”>$ip\”{
设置当前时间\[时钟秒\]
如果{\$currentTime<\$endTime}{
如果{\[信息存在等待($ip)\]}{
lappend发现$ip
未设置等待($ip)
}
如果{\[array size waiting\]}exp\u继续
}
}\n“
}
#设置预期超时并为tcpdump结果创建空列表
设置超时$tcpdump\u超时
已找到集合[列表]
未找到集合[列表]
#启动tcpdump
发送“tcpdump-i ixp1\r”
期望“tcpdump:侦听ixp1”
#获取停止tcpdump的时间
设置结束时间[expr[时钟秒数]+$tcpdump\u超时]
#将expbody输入expect;它是运行时生成的,这一点也不为人所知
期望$expbody
未找到集合[array names waiting]
取消等待
#发送^c以停止tcpdump
发送--“\003”
期望“#”

谢谢你,唐娜!这无疑让我走上了正确的道路,但我仍然有一些问题。我现在的主要问题是tcpdump不断地从多播列表中的地址接收多播数据包。因此,一旦expect看到225.0.0.1中的数据包,它就会将其添加到查找列表中,这非常好。但随后它将从同一地址接收另一个数据包,expect将再次触发,而不是忽略它。这会导致expectbody从不超时。还有,你的代码我得到一个错误,因为它试图从等待名单中删除地址,即使它已经被删除。。。
set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3}
set tcpdump_timeout 10

spawn /bin/bash
expect "] "

# Create the runtime-generated expbody to use later
# Generate the timeout clause as a normal literal
set expbody {
timeout {
    set not_found [array names waiting]
    unset waiting
}
}
foreach ip $multicast_list {
    set waiting($ip) "dummy"
    # Generate the per-ip clause as a multi-line string; beware a few backslashes
    append expbody "\"> $ip\" {
    set currentTime \[clock seconds\]
    if { \$currentTime < \$endTime } {
      if { \[ info exists waiting($ip) \] } {
        lappend found $ip
        unset waiting($ip)
      }
      if {\[array size waiting\]} exp_continue
    }
}\n"
}

# Set expect timeout and create empty lists for tcpdump results
set timeout $tcpdump_timeout
set found [list]
set not_found [list]

# Start tcpdump
send "tcpdump -i ixp1\r"
expect "tcpdump: listening on ixp1"

# Get the time to stop tcpdump
set endTime [ expr [clock seconds] + $tcpdump_timeout ]

# Feed expbody into expect; it's none-the-wiser that it was runtime-generated
expect $expbody
set not_found [array names waiting]
unset waiting
# Send ^c to stop tcpdump
send -- "\003"
expect "# "