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

/bin/expect $expect_out multiple regex matches

我正在使用以下 expect(1) script to receive a list of users on a Teamspeak server using the Telnet Server Query

#!/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

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

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

问题:


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

有很多方法可以解决这个问题,但最自然的方法可能是执行以下步骤:首先,不要单独使用 expectset 行,而是使用执行 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
}

要将 clid 变成列表(在 tcl 中实际上只是一个字符串),请使用列表命令:

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

现在您可以使用

遍历列表
foreach id $clid { puts $id }

你现在应该考虑如何检测clientlist命令输出的结束,这样你就可以匹配它而不是因为超时而停止。 (Post 如果你的进度受阻,一个新问题)。

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
}