Анализ вывода сканирования IW wlan0

Я написал сценарий wlan manager для обработки открытых/ad-hoc/wep / WPA2 сетей. Теперь я пытаюсь проанализировать вывод сканирования IW wlan0, чтобы получить хорошую функцию сканирования для моего скрипта. Моя цель - получить такой результат:

SSID        channel     signal      encryption
wlan-ap     6           70%         wpa2-psk
test        1           55%         wep

то, что я уже получил, выводится следующим образом:

$ iw wlan0 scan | grep 'SSID|freq|signal|capability' | tac
SSID: Koti783
signal: -82.00 dBm
capability: ESS Privacy ShortPreamble SpectrumMgmt ShortSlotTime (0x0531)
freq: 2437

Я пытался изучить bash/sed / awk, но еще не нашел способ достичь того, что я пытаюсь. Так как же этого достичь?

6 ответов


вот мое окончательное решение на основе Sudo_O ответ:

 == "BSS" {
    MAC = 
    wifi[MAC]["enc"] = "Open"
}
 == "SSID:" {
    wifi[MAC]["SSID"] = 
}
 == "freq:" {
    wifi[MAC]["freq"] = $NF
}
 == "signal:" {
    wifi[MAC]["sig"] =  " " 
}
 == "WPA:" {
    wifi[MAC]["enc"] = "WPA"
}
 == "WEP:" {
    wifi[MAC]["enc"] = "WEP"
}
END {
    printf "%s\t\t%s\t%s\t\t%s\n","SSID","Frequency","Signal","Encryption"

    for (w in wifi) {
        printf "%s\t\t%s\t\t%s\t%s\n",wifi[w]["SSID"],wifi[w]["freq"],wifi[w]["sig"],wifi[w]["enc"]
    }
}'

выход:

$ sudo iw wlan0 scan | awk -f scan.awk
SSID        Frequency   Signal      Encryption
netti       2437        -31.00 dBm  Open
Koti783     2437        -84.00 dBm  WPA
WLAN-AP     2462        -85.00 dBm  WPA

здесь GNU awk скрипт, чтобы вы собирались, который захватывает SSIDs и канал для каждого уникального BSS:

/^BSS / {
    MAC = 
}
/SSID/ {
    wifi[MAC]["SSID"] = 
}
/primary channel/ {
    wifi[MAC]["channel"] = $NF
}

# Insert new block here

END {
    printf "%s\t\t%s\n","SSID","channel"

    for (w in wifi) {
        printf "%s\t\t%s\n",wifi[w]["SSID"],wifi[w]["channel"]
    }
}

это должно быть легко для вас, чтобы добавить новые блоки для сигнала и шифрования, учитывая все изучение вы делали.

сохраните скрипт в файл, например wifi.awk и бежать как:

$ sudo iw wlan0 scan | awk -f wifi.awk

выход будет в отформатированном запрошенном:

SSID        channel
wlan-ap     6
test        1

как правило, плохая практика - пытаться анализировать сложный вывод программ, предназначенных для чтения людьми (а не машинами для анализа).

например, вывод iw может меняться в зависимости от языковых настроек системы и/или версия iw, оставляя вас с "менеджером", который работает только на вашей машине разработки.

вы можете использовать тот же интерфейс, что iw использует для получения информации: бэкэнд библиотеки libnl

вы также можете взглянуть на wireless-tools (iwconfig, iwlist,...) которые используют libiw библиотека.


вот простая функция Bash, которая использует исключительно внутренние элементы Bash и порождает только одну под-оболочку:

#!/bin/bash 
function iwScan() {
   # disable globbing to avoid surprises
   set -o noglob
   # make temporary variables local to our function
   local AP S
   # read stdin of the function into AP variable
   while read -r AP; do
     ## print lines only containing needed fields
     [[ "${AP//'SSID: '*}" == '' ]] && printf '%b' "${AP/'SSID: '}\n"
     [[ "${AP//'signal: '*}" == '' ]] && ( S=( ${AP/'signal: '} ); printf '%b' "${S[0]},";)
   done
   set +o noglob
}

iwScan <<< "$(iw wlan0 scan)"

выход:

-66.00,FRITZ!Box 7312
-56.00,ALICE-WLAN01
-78.00,o2-WLAN93
-78.00,EasyBox-7A2302
-62.00,dlink
-74.00,EasyBox-59DF56
-76.00,BELAYS_Network
-82.00,o2-WLAN20
-82.00,BPPvM

функция может быть легко изменена, чтобы предоставить дополнительные поля, добавив необходимый фильтр в while read-r AP while-loop, например:

[[ "${AP//'last seen: '*}" == '' ]] && ( S=( ${AP/'last seen: '} ); printf '%b' "${S[0]},";)

выход:

-64.00,1000,FRITZ!Box 7312
-54.00,492,ALICE-WLAN01
-76.00,2588,o2-WLAN93
-78.00,652,LN8-Gast
-72.00,2916,WHITE-BOX
-66.00,288,ALICE-WLAN
-78.00,800,EasyBox-59DF56
-80.00,720,EasyBox-7A2302
-84.00,596,ALICE-WLAN08

Я использую такое решение для openwrt:

wlan_scan.sh

#!/bin/sh
sudo iw dev wlan0 scan | awk -f wlan_scan.awk | sort

wlan_scan.на awk

/^BSS/ {
    mac = gensub ( /^BSS[[:space:]]*([0-9a-fA-F:]+).*?$/, "\1", "g",  );
}
/^[[:space:]]*signal:/ {
    signal = gensub ( /^[[:space:]]*signal:[[:space:]]*(\-?[0-9.]+).*?$/, "\1", "g",  );
}
/^[[:space:]]*SSID:/ {
    ssid = gensub ( /^[[:space:]]*SSID:[[:space:]]*([^\n]*).*?$/, "\1", "g",  );
    printf ( "%s %s %s\n", signal, mac, ssid );
}

результат

-62.00 c8:64:c7:54:d9:05 a
-72.00 70:72:3c:1c:af:17 b
-81.00 78:f5:fd:be:33:cb c

в сценарии awk выше есть ошибка.

следующий код не будет работать, если SSID имеет пробелы в имени. Полученный результат будет первым маркером только имени SSID.

 == "SSID:" {
    wifi[MAC]["SSID"] = 
}

при печати $0, $1, $2:

:     SSID: DIRECT-82-HP OfficeJet 8700
: SSID:
: DIRECT-82-HP

одно из возможных решений-взять substr $0, который содержит ведущие пробелы, токен "SSID:" и предоставленное имя сети с несколькими токенами.

какие-то другие предложения?