0

I'm using the following 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"

This produces an output like this:

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

Then, I can use the following code to get the client id (clid=*) of the first user;

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

Questions:

  • How can I get a list of all the client ids (clid=*)
  • Can I loop over them using a for/foreach?

I've tried to use the accepted answer in this question: How do I extract all matches with a Tcl regex?, however I'm so far unable to apply it on the output of a send, instead of a variable

oguz ismail
  • 1
  • 16
  • 47
  • 69
0stone0
  • 34,288
  • 4
  • 39
  • 64

2 Answers2

2

There are many ways to handle this, but the most natural might be to go by these steps: first, instead of separate expect and set lines, use the facility of doing the set as result of a match:

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

This is slightly better as clid will only be set if the pattern matches. The next step is then to use the command exp_continue to restart the matching process. It is like a for loop. See man expect.

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

To make clid into a list (which in tcl is really just a string), use the list commands:

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

Now you can iterate through the list with

foreach id $clid { puts $id }

You should now think about how to detect the end of the output of the clientlist command, so that you can match it instead of stopping due to a timeout. (Post a new question if blocked in your progress).

meuh
  • 11,500
  • 2
  • 29
  • 45
  • Thanks a lot! I'm able to loop over all the ID's. The *you should now think about how to detect the end of the output of the clientlist command* still needs some debugging, I'll guess I'll need to research the behaviour of `exp_continue` some more! I'll accept your answer if there aren't any other solutions posted.w – 0stone0 Feb 22 '21 at 14:24
0

expect uses \r\n as line endings. Try this:

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
}
glenn jackman
  • 238,783
  • 38
  • 220
  • 352