/bin/expect $expect_out 多个正则表达式匹配

问题描述

我正在使用以下 expect(1) 脚本通过 Telnet Server Query 接收 Teamspeak 服务器上的用户列表。

#!/usr/bin/expect

# Spawn TELNET
spawn telnet example.com 10000
expect "TS3"

# Login
send "login $USER $PASS\r"

# Set serverID
send "use sid=$SSID\r"
expect "error id=0 msg=ok"

# Get clients
send "clientlist\r"

这会产生如下输出

clid=512 cid=3 client_database_id=4 client_nickname=User1 client_type=1|clid=486 cid=3 client_database_id=26 client_nickname=User2 client_type=0

然后,我可以使用下面的代码获取一个用户的客户端ID(clid=*);

# Get clients
send "clientlist\r"
expect -re "clid=(\\d+) "
set clid $expect_out(1,string)
puts "$clid"
# Output: 512

问题

  • 如何获取所有客户端 ID 的列表 (clid=*)
  • 我可以使用 for/foreach 循环遍历它们吗?

我尝试在这个问题中使用公认的答案:How do I extract all matches with a Tcl regex?,但是到目前为止我无法将它应用于 send输出,而不是变量

解决方法

有很多方法可以解决这个问题,但最自然的方法可能是按照以下步骤进行:首先,不要使用单独的 expectset 行,而是使用 {{1} }} 匹配结果:

set

这稍微好一些,因为只有在模式匹配时才会设置 expect -re "clid=(\\d+) " { set clid $expect_out(1,string) } puts "$clid" 。 下一步是使用命令 clid 重新启动匹配过程。它就像一个 exp_continue 循环。请参阅for

man expect

要将 expect -re "clid=(\\d+) " { set clid $expect_out(1,string) puts "$clid" exp_continue } 变成一个列表(在 tcl 中实际上只是一个字符串),请使用列表命令:

clid

现在您可以使用

遍历列表
expect -re "clid=(\\d+) " { 
 lappend clid $expect_out(1,string)
 exp_continue
}
puts "$clid"

您现在应该考虑如何检测 foreach id $clid { puts $id } 命令的输出结束,以便您可以匹配它而不是因为超时而停止。 (如果您的进度被阻止,请发布一个新问题)。

,

expect 使用 \r\n 作为行尾。试试这个:

send "clientlist\r"
expect -re {clientlist\r\n(.+)\r\n}
set ids {}
foreach {_ id} [regexp -all -inline {clid=(\d+)} $expect_out(1,string)] {
    lappend ids $id
}