bash 解析 iw wlan0 扫描输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17809912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parsing iw wlan0 scan output
提问by Ari Malinen
I wrote wlan manager script to handle open/ad-hoc/wep/wpa2 networks. Now im trying to parse iw wlan0 scan output to get nice scan feature to my script. My goal is to get output like this :
我编写了 wlan 管理器脚本来处理 open/ad-hoc/wep/wpa2 网络。现在我正在尝试解析 iw wlan0 扫描输出,以便为我的脚本提供不错的扫描功能。我的目标是获得这样的输出:
SSID channel signal encryption
wlan-ap 6 70% wpa2-psk
test 1 55% wep
What i have achived already is output like this :
我已经实现的是这样的输出:
$ iw wlan0 scan | grep 'SSID\|freq\|signal\|capability' | tac
SSID: Koti783
signal: -82.00 dBm
capability: ESS Privacy ShortPreamble SpectrumMgmt ShortSlotTime (0x0531)
freq: 2437
I have been trying to study bash/sed/awk but havent found yet a way to achieve what im trying. So what is good way to achieve that?
我一直在尝试学习 bash/sed/awk,但还没有找到一种方法来实现我的尝试。那么实现这一目标的好方法是什么?
回答by Ari Malinen
Here is my final solution based of Sudo_O answer:
这是我基于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"]
}
}'
Output:
输出:
$ 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
回答by uml?ute
it's generally bad practice to try parsing complex output of programs intended for humans to read (rather than machines to parse).
尝试解析供人类阅读(而不是机器解析)的程序的复杂输出通常是不好的做法。
e.g. the output of iw
might change depending on the language settings of the system and/or the version of iw
, leaving you with a "manager" that only works on your development machine.
例如, 的输出iw
可能会根据系统的语言设置和/或 的版本而改变iw
,让您拥有一个只能在您的开发机器上运行的“管理器”。
instead you might use the same interface that iw
uses to get it's information: the library backend libnl
相反,您可以使用iw
用于获取其信息的相同接口:库后端libnl
you might also want to have a look at the wireless-tools
(iwconfig
, iwlist
,...) that use the libiwlibrary.
您可能还想查看使用libiw库的wireless-tools
( iwconfig
, iwlist
,...) 。
回答by Chris Seymour
Here is an GNU awk
script to get you going that grabs the SSIDs and the channel for each unique BSS:
这是一个GNU awk
脚本,可以帮助您获取每个唯一 BSS 的 SSID 和频道:
/^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"]
}
}
It should be easy for you to add the new blocks for signal and encryption considering all the studying you have been doing.
考虑到您一直在进行的所有研究,您应该很容易为信号和加密添加新块。
Save the script to file such as wifi.awk
and run like:
将脚本保存到文件,例如wifi.awk
并运行:
$ sudo iw wlan0 scan | awk -f wifi.awk
The output will be in the formatted requested:
输出将采用所要求的格式:
SSID channel
wlan-ap 6
test 1
回答by binary koala
Here is a simple Bash function which uses exclusively Bash internals and spawns only one sub-shell:
这是一个简单的 Bash 函数,它只使用 Bash 内部结构并且只产生一个子 shell:
#!/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)"
Output:
输出:
-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
The function can be easily modified to provide additional fields by adding a necessary filter into the while read -r AP while-loop, eg:
通过在 while read -r AP while-loop 中添加必要的过滤器,可以轻松修改该函数以提供其他字段,例如:
[[ "${AP//'last seen: '*}" == '' ]] && ( S=( ${AP/'last seen: '} ); printf '%b' "${S[0]},";)
Output:
输出:
-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
回答by puchu
I am using such solution for openwrt:
我正在为 openwrt 使用这样的解决方案:
wlan_scan.sh
wlan_scan.sh
#!/bin/sh
sudo iw dev wlan0 scan | awk -f wlan_scan.awk | sort
wlan_scan.awk
wlan_scan.awk
/^BSS/ {
mac = gensub ( /^BSS[[:space:]]*([0-9a-fA-F:]+).*?$/, "\1", "g", -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
);
}
/^[[:space:]]*signal:/ {
signal = gensub ( /^[[:space:]]*signal:[[:space:]]*(\-?[0-9.]+).*?$/, "\1", "g", == "SSID:" {
wifi[MAC]["SSID"] =
}
);
}
/^[[:space:]]*SSID:/ {
ssid = gensub ( /^[[:space:]]*SSID:[[:space:]]*([^\n]*).*?$/, "\1", "g", #!/usr/bin/env awk -f
~ /^BSS/ {
if( !~ /Load:/) { #< Escape "BBS Load:" line
gsub("(\(.*|:)", "", )
MAC = toupper()
wifi[MAC]["enc"] = "OPEN"
wifi[MAC]["WPS"] = "no"
wifi[MAC]["wpa1"] = ""
wifi[MAC]["wpa2"] = ""
wifi[MAC]["wep"] = ""
}
}
== "SSID:" {
# Workaround spaces in SSID
FS=":" #< Changing field separator on ":", it should be
# forbidded sign for SSID name
A5FEF2C499BB:test-ssid2:OPEN:no:9:43:0d00h00m
039EFACA9A8B:test-ssid2:WPA1:no:9:33:0d00h00m
038BF3C1988B:test-ssid2:WPA2:no:9:35:0d00h00m
028EF3C2997B:test-ssid2:WPA1:no:9:35:0d00h03m
=##代码##
sub(" ", "", ) #< remove first whitespace
wifi[MAC]["SSID"] =
FS=" "
##代码##=##代码##
}
== "capability:" {
for(i=2; i<=NF; i++) {
if($i ~ /0x[0-9]{4}/) {
gsub("(\(|\))", "", $i)
if (and(strtonum($i), 0x10))
wifi[MAC]["wep"] = "WEP"
}
}
}
== "WPA:" {
wifi[MAC]["wpa1"] = "WPA1"
}
== "RSN:" {
wifi[MAC]["wpa2"] = "WPA2"
}
== "WPS:" {
wifi[MAC]["WPS"] = "yes"
}
== "DS" {
wifi[MAC]["Ch"] =
}
== "signal:" {
match(, /-([0-9]{2})\.00/, m)
wifi[MAC]["Sig"] = m[1]
}
== "TSF:" {
gsub("(\(|d|,)", "", )
match(, /([0-9]{2}):([0-9]{2}):/, m)
day =
hour = m[1]
min = m[2]
wifi[MAC]["TSF"] = day"d"hour"h"min"m"
}
END {
for (w in wifi) {
if (wifi[w]["wep"]) {
if (wifi[w]["wpa1"] || wifi[w]["wpa2"])
wifi[w]["enc"] = wifi[w]["wpa1"]wifi[w]["wpa2"]
else
wifi[w]["enc"] = "WEP"
}
printf "%s:%s:%s:%s:%s:%s:%s\n", w, wifi[w]["SSID"], wifi[w]["enc"], \
wifi[w]["WPS"], wifi[w]["Ch"], wifi[w]["Sig"], wifi[w]["TSF"]
}
}
: SSID: DIRECT-82-HP OfficeJet 8700
: SSID:
: DIRECT-82-HP
);
printf ( "%s %s %s\n", signal, mac, ssid );
}
result
结果
##代码##回答by ericshufro
There is a bug in the awk script above.
上面的 awk 脚本中有一个错误。
The following code will not work if the SSID has spaces in the name. The received result will be the first token of the SSID name only.
如果 SSID 名称中有空格,以下代码将不起作用。接收到的结果将仅是 SSID 名称的第一个标记。
##代码##When printing $0, $1, $2:
打印 $0、$1、$2 时:
##代码##One possibly solution is to take a substr of $0 which contains leading spaces, the token "SSID: " and the provided multi-token network name.
一种可能的解决方案是采用 $0 的子字符串,其中包含前导空格、令牌“SSID:”和提供的多令牌网络名称。
Any other suggestions?
还有其他建议吗?
回答by cy8g3n
I've taken awk code from Ari Malinenand reworked it a bit, because iw output is not stable and changes, also there are other issues like spaces in SSID. I put it on githubin case if I'll change it in the future.
我从Ari Malinen获取了 awk 代码并对其进行了一些修改,因为 iw 输出不稳定并且会发生变化,还有其他问题,例如 SSID 中的空格。我把它放在github上,以防我将来改变它。
##代码##Output:
输出:
##代码##if you wonder what if($2 !~ /Load:/)
does, well on some routers there might be "BSS Load:" string.
如果您想知道是什么if($2 !~ /Load:/)
,那么在某些路由器上可能会有“BSS Load:”字符串。