问题描述
我正在使用以下 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
的输出,而不是变量
解决方法
有很多方法可以解决这个问题,但最自然的方法可能是按照以下步骤进行:首先,不要使用单独的 expect
和 set
行,而是使用 {{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
}