1

I am running a Teamspeak 3 server on a Ubuntu server and I would like to fetch the clients currently connected using a script.

The script currently outputs this from the Teamspeak Server Query:

clid=1 cid=11 client_database_id=161 client_nickname=Music client_type=1|clid=3 cid=11 client_database_id=153 client_nickname=Music\sBot client_type=0|clid=5 cid=1 client_database_id=68 client_nickname=Unknown\sfrom\s127.0.0.1:52537 client_type=1|clid=12 cid=11 client_database_id=3 client_nickname=FriendlyMan client_type=0|clid=16 cid=11 client_database_id=161 client_nickname=Windows\s10\sUser client_type=0|clid=20 cid=11 client_database_id=225 client_nickname=3C2J0N47H4N client_type=0

How can I extract the nicknames from this mess? More Specifically only the ones that contain "client_type=0".

Played around with GREP (grep -E -o 'client_nickname=\w+'), close to what I want.

client_nickname=Music
client_nickname=Music
client_nickname=Unknown
client_nickname=FriendlyMan
client_nickname=Windows
client_nickname=3C2J0N47H4N

Desired Output:

Music Bot,FriendlyMan,Windows 10 User,3C2J0N47H4N

1 Answers1

0

Our input consists of a single line:

$ cat file
clid=1 cid=11 client_database_id=161 client_nickname=Music client_type=1|clid=3 cid=11 client_database_id=153 client_nickname=Music\sBot client_type=0|clid=5 cid=1 client_database_id=68 client_nickname=Unknown\sfrom\s127.0.0.1:52537 client_type=1|clid=12 cid=11 client_database_id=3 client_nickname=FriendlyMan client_type=0|clid=16 cid=11 client_database_id=161 client_nickname=Windows\s10\sUser client_type=0|clid=20 cid=11 client_database_id=225 client_nickname=3C2J0N47H4N client_type=0

Using grep + sed

Here is one approach that starts with grep and then uses sed to cleanup to the final format:

$ grep -oP '(?<=client_nickname=)[^=]+(?=client_type=0)' file | sed -nE 's/\\s/ /g; H;1h; ${x; s/ *\n/,/g;p}'
Music Bot,FriendlyMan,Windows 10 User,3C2J0N47H4N

Using awk

Here is another approach that just uses awk:

$ awk -F'[= ]' '/client_type=0/{gsub(/\\s/, " ", $8); printf (f?",":"")$8; f=1} END{print ""}' RS='|' file
Music Bot,FriendlyMan,Windows 10 User,3C2J0N47H4N

The awk code uses | as the record separator and awk reads in one record at a time. Each record is divided into fields with the field separator being either a space or an equal sign. If the record contains the text client_type=0, then we replace all occurrences of \s in field 8 with space and then print the resulting field 8.

Using bash

#!/bin/bash
sep=
( cat file; echo "|"; ) | while read -r -d\| clid cid db name type misc
do
    [ "$type" = "client_type=0" ] || continue
    name=${name//\\s/ }
    printf "%s%s" "$sep" "${name#client_nickname=}"
    sep=,
done
echo ""

This produces the output:

Music Bot,FriendlyMan,Windows 10 User,3C2J0N47H4N
John1024
  • 109,961
  • 14
  • 137
  • 171
  • Wow that's complicated... Too advanced for me anyways. It Works! – CR33P1N3V1L May 03 '16 at 03:03
  • I should start playing around with these text manipulators, they come in handy alot. – CR33P1N3V1L May 03 '16 at 03:12
  • @CR33P1N3V1L Yes, both `sed` and `awk` come in quite handy. – John1024 May 03 '16 at 03:38
  • I ran into a problem with the awk approach. The first users name was replaced with "type". I had that user re-log and it fixed it. I tried the grep + sed approach while the awk was having that glitch and it worked fine. Using the grep + sed for now. – CR33P1N3V1L May 03 '16 at 20:03
  • @CR33P1N3V1L I'm glad `grep`+`sed` is working for you. If you show me the input that confused the `awk` code, I'll see what I can do with it. – John1024 May 03 '16 at 20:45