5

I'm trying to parse the results of nmcli dev wifi which produces a result like this:

*  SSID                 MODE   CHAN  RATE       SIGNAL  BARS  SECURITY  
   Prk                  Infra  11    54 Mbit/s  99      ▂▄▆█            
   VIDEOTRON2255        Infra  11    54 Mbit/s  67      ▂▄▆_  WPA1 WPA2 
   a space              Infra  6     54 Mbit/s  65      ▂▄▆_  WPA2      
*  TNCAP4D0B18          Infra  11    54 Mbit/s  52      ▂▄__            

Initially I was just parsing using awk -F" " which worked for almost all cases. I'm finding any wifi network with a space in it throws this off completely.

So I instead try using two spaces instead of one this didn't produce the results I expected. How can I consistently parse the columns in the above output?

Current script is something like this:

nmcli dev wifi | sed 's/\*//g' > /tmp/scan
networks=$(cat /tmp/scan | awk -F"  " '{print $1}' | sed '1d')
# ...
bars=$(cat /tmp/scan | awk -F"  " '{print $6}' | sed '1d')
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Philip Kirkbride
  • 9,816
  • 25
  • 95
  • 167
  • what about `awk -F'\t'`? – jesse_b Oct 19 '17 at 19:02
  • @Jesse_b just tried it now and didn't work – Philip Kirkbride Oct 19 '17 at 19:04
  • it's not clear. what do you want to put in the networks and bars variables? in the booth case I typed awk command without '-F' option : I've got the list of the networks and the db of the signal. – dubis Oct 19 '17 at 19:14
  • 2
    At least with recent versions of `nmcli`, you can avoid needing to parse the output by specifying exactly what fields you want (and in what order) e.g. `networks=$(nmcli -t -f ssid dev wifi)`. There's also an option to print in a machine-parsable mode. – steeldriver Oct 19 '17 at 19:15
  • @dubis that is what you should have but it won't work if a wifi network has a space in the name. – Philip Kirkbride Oct 19 '17 at 19:18
  • @steeldriver good to know but I'm afraid of using that approach. If each time I run `nmcli` the wifi is again scanned how can I be sure that the network list won't have changed? (e.g. could I be sure the 7th entry in the SSID field is actually the same network as the 7th entry in the security field) – Philip Kirkbride Oct 19 '17 at 19:19
  • Huh? what does that have to do with how you parse it? What is the actual problem you are trying to solve here? – steeldriver Oct 19 '17 at 19:25
  • @steeldriver I'm converting `nmcli` into a json object to be passed to web developers as an api. – Philip Kirkbride Oct 19 '17 at 19:26
  • 2
    In that case you should (IMHO) almost certainly using the `--mode multiline` format if your version of `nmcli` supports it - which gives you colon-delimited key-value pairs out of the box – steeldriver Oct 19 '17 at 19:40

2 Answers2

11
awk -F' {2,}' # means - two or more spaces.

or

awk -F'  +' # means - one space, then one or more spaces.

This commands mean the same - use 2 or more spaces as fields delimiter.

MiniMax
  • 4,025
  • 1
  • 17
  • 32
3

Parse the first line to find at which position each column starts, then parse the other lines based on column numbers. For example, the following script prints column 2 which is the SSID.

nmcli_output=$(nmcli dev wifi)
printf %s\\n "$nmcli_output" | awk -v column=2 '
    NR==1 {
        i=1; p=1;
        while(match($0,/^[^ ]+ +/)) {
            a[i++] = p;
            p += RLENGTH;
            $0 = substr($0, RLENGTH+1);
        }
    }
    NR!=1 {
        text = substr($0, a[column], a[column+1] ? a[column+1]-a[column] : length);
        sub(text, / +$/, "");
        print text
    }'

Depending on what you want to do, calling awk multiple times may not be the best solution. Keep in mind that you can run shell commands from awk with the system function.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175