Search code examples
grepubuntu-serverteamspeak

Linux Text Extraction GREP


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

Solution

  • 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