CSV from ‘iw’ output

Published: Thu 23 October 2014

Intro

A long and lingering issue with wireless 802.11 work in a UNIX context is filtering AP scans into a meaningful form such that the important bits (BSSID, ESSID, channel) can be used by shell scripts, PHP, etc.

This is something grappled by many with ‘iwlist’, but as it is now legacy (along with ‘iwconfig’) across Linux distributions, a migration of scripts to ‘iw’ is required to ensure portability.

Here is a short script that will take the output of a scan and place it into a formatted CSV with fields on a single line, like so:

BSSID, freq (MHz), RSSI (dBms), ESSID, channel


24:65:12:85:3a:45,2412,-76.00,FRITZ!Box 7312,1
00:90:3c:c0:01:01,2457,-48.00,noonicorn,10
c0:15:02:c7:d6:45,2412,-86.00,FRITZ!Box Fon WLAN 71,1
74:3b:70:6b:22:4c,2422,-79.00,Don't Menschen IT,3
e8:9c:a6:3d:c6:1a,2412,-71.00,Superglue-c81a-rescue,1
00:25:fe:a7:af:1c,2417,-84.00,Funkwrecker,2
71:32:71:e7:25:bf,2417,-79.00,WLAN-E72519,2

It takes care of ESSIDs with awkward characters, such as ‘!’ and whitespace.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
# Scan APs with 'iw' and output to single-line. 
# CSV is in the format:
#   BSSID, freq (MHz), RSSI (dBms), ESSID, channel) 
# Tested with iw version 3.15 on OpenWrt and 3.4 on Debian GNU/Linux

DATA=/path/to/data
NIC=$(iw dev | grep Interface | awk '{ print $2 }')
TMPFILE=/tmp/scan.log
SCAN=$DATA/networks
S=1;E=5;

# Scrape 'iw' scan output and write to temporary file
iw dev $NIC scan | grep -E '^BSS|SSID|DS Parameter set: channel|signal:|freq:'\
| sed -e 's/BSS\ //' -e 's/(on.*$//'  -e 's/DS Parameter\ set:\ channel\ // ' \
-e 's/SSID:\ //' -e 's/freq://' -e 's/signal: //' -e 's/dBm//'\
    > $TMPFILE && LEN=$(cat $TMPFILE | wc -l)

# Count lines in 5's
for i in $(seq 1 $((LEN/5)))
    do
        LINES=$(sed -n "$S,$E p;$E q" $TMPFILE)
        # Test for hidden ESSIDs. Allow for ESSIDs with spaces
        if [ $(echo $LINES | awk '{print substr($0, index($0,$4))}' | sed \
            's/\(.*\)[[:space:]].*/\1/' | wc -c )  -gt 1 ]
            then
                # Replace all whitespace with commas except whitespace in
                # ESSID field
                echo $LINES | awk -F ' ' -v OFS=',' '{print $1, $2, $3, \
                substr($0, index($0,$4))}' | sed 's/\(.*\)[[:space:]]/\1,/'
        fi
        # Increment
            ((S+=5))
            ((E+=5))
    done > $SCAN
rm $TMPFILE

Save it out as scan.sh then:

$ chmod +x scan.sh
$ sudo ./scan.sh && cat /path/to/data/networks

Output can be read straight into variables in a script, like so:

1
2
3
4
5
6
7
8
#!/bin/bash

...

while IFS=, read BSSID FREQ RSSI ESSID CHANNEL
    do
        # Do something with these variables here. 
    done < /path/to/data/networks

Affiliated