0

I'm trying to process output from nmcli command (colon separated values), but failing to handle / ignore escaped colons in MAC or BSSID. I've tried awk, jq, sed, regex but just not getting it...

piped command:

nmcli -f SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY -t dev wifi

example output:

WiFi:00\:0A\:97\:6F\:7B\:AC:165:5660 MHz:15:

If I move BSSID to the end of the line / field's list (and then just cut the last field) it'll work, but now it's a matter a pride. Please help!

I did find this existing stackoverflow thread, which really went about it nicely, but I'm ultimatly running into the same problem of how to ignore the escaped colon in the MAC!@%$ address: parse colon separated value pairs

Most recent (readable) attempt:

printf '%s' "$(nmcli -f SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY -t dev wifi)" | jq -sR 'split("\n") | map(split(":")) | map({"SSID": .[0], "BSSID": .[1], "CHAN": .[2], "RATE": .[3], "FREQ": .[4], "SIGNAL": .[5], "SECURITY": .[6]})'

and problem output:

...
{
"SSID": "WiFi",
"BSSID": "00\\",
"CHAN": "0A\\",
"RATE": "97\\",
"FREQ": "6F\\",
"SIGNAL": "7B\\",
"SECURITY": "AC"
},
...

Would also need JQ to leave colons in place and not escape as shown above, if at all possible, ... please don't just say python...

closed as unclear what you're asking by Jeff Schaller May 12 at 20:55

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    what's the desired end-state? 6 variables? a CSV file? – Jeff Schaller Mar 21 '18 at 0:23
  • read will do it, as will cut. split on colons, then ask for fields 1, 2-7, 8,9,10, and 11. – Jeff Schaller Mar 21 '18 at 0:43
  • 2
    Please don't make more work for other people by vandalizing your posts. By posting on the Stack Exchange (SE) network, you've granted a non-revocable right, under the CC BY-SA 3.0 license for SE to distribute that content. By SE policy, any vandalism will be reverted. If you want to know more about deleting a post, consider taking a look at: How does deleting work? – iBooot May 12 at 20:25
3

A few notes here:

  • You can prevent nmcli from escaping the fields with --escape/-e no
  • You don't have to quote json field names (without special characters)
  • SSID and Security don't always get returned so I added a placeholder (--)

    printf '%s' "$(nmcli -f SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY -e no -t dev wifi)" |
      jq -sR 'split("\n") |
        map(split(":") |
        {SSID: (if .[0] == "" then "--" else .[0] end), 
          BSSID: .[1:6] | join(":"),
          CHAN: .[7],
          FREQ: .[8],
          SIGNAL: .[9],
          SECURITY: (if .[10]  == "" then "--" else .[10] end)})'
    
2

Perl allows you to construct a field separator with lookbehind - and also handily provides a JSON module. So you could do something like

nmcli -f SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY -t dev wifi | 
  perl -F'(?<!\\):' -MJSON=encode_json -lne 'print encode_json([map { s/\\:/:/g ; $_ } @F])'

Testing with your example nmcli output:

printf 'WiFi:00\:0A\:97\:6F\:7B\:AC:165:5660 MHz:15:' | 
  perl -F'(?<!\\):' -MJSON=encode_json -lne 'print encode_json([map { s/\\:/:/g ; $_ } @F])'
["WiFi","00:0A:97:6F:7B:AC","165","5660 MHz","15"]
  • 1
    @LordVance FWIW on Ubuntu, I simply had to install the libjson-perl package – steeldriver Mar 21 '18 at 1:07
2

Using sed to clean the data, and mlr to turn it into JSON:

h='SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY'
nmcli -f $h -t dev wifi | 
sed 's/^:/"",/;s/\([^\]\):/\1,/g;s/[\]:/:/g' | 
mlr --c2j --jvstack  --jlistwrap  label $h

Output example:

{
  "SSID": "FooBarBaz",
  "BSSID": "13:F6:8C:56:9B:3B",
  "CHAN": 36,
  "FREQ": "5180 MHz",
  "SIGNAL": 20,
  "SECURITY": "WPA1 WPA2"
},
1

GNU awk can handle fields as sequences of either escaped characters or non-colon-nor-backslash characters (see this answer), so the following should work. Not very efficient, but at least a solution...

#!/bin/bash
line="WiFi:00\:0A\:97\:6F\:7B\:AC:165:5660 MHz:15:"
# line=`nmcli -f SSID,BSSID,CHAN,FREQ,SIGNAL,SECURITY -t dev wifi`
for i in 1 2 3 4 5; do
    echo $line | gawk -v FPAT='(\\\\.|[^\\\\:])*' '{print $'$i'}' 
done

Not the answer you're looking for? Browse other questions tagged or ask your own question.