LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Help needed for using awk to parse a file to make array for bash script (https://www.linuxquestions.org/questions/programming-9/help-needed-for-using-awk-to-parse-a-file-to-make-array-for-bash-script-632698/)

tallmtt 04-03-2008 08:04 AM

Help needed for using awk to parse a file to make array for bash script
 
I am trying to write a script that will run "iwlist <interface> scanning >> iwlist-file."

Then I want to parse the file so that the ESSID, AP, encryption key off vs on, and signal strength all become variables that I will be able to use in the script.

I will have some preferred networks with special static vs dhcp connections that if that ESSID is available, a different script will run (say in same directory named by network) but if no network is found, it would prioritize the available networks with Encryption key off by signal strength and connect automatically to it.

The file I need to parse to obtain those variables would look something like this:

Code:

BigDog tallmtt # iwlist ath0 scanning
ath0      Scan completed :
          Cell 01 - Address: 00:06:25:E7:29:5F
                    ESSID:"Home"
                    Mode:Master
                    Frequency:2.437 GHz (Channel 6)
                    Quality=38/70  Signal level=-57 dBm  Noise level=-95 dBm
                    Encryption key:off
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s
                    Extra:bcn_int=100
          Cell 02 - Address: 00:18:4D:92:D5:B6
                    ESSID:"NETGEAR"
                    Mode:Master
                    Frequency:2.462 GHz (Channel 11)
                    Quality=7/70  Signal level=-88 dBm  Noise level=-95 dBm
                    Encryption key:off
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
                              24 Mb/s; 36 Mb/s; 54 Mb/s; 6 Mb/s; 9 Mb/s
                              12 Mb/s; 48 Mb/s
                    Extra:bcn_int=100
          Cell 03 - Address: 00:1C:10:47:6E:50
                    ESSID:"linksys"
                    Mode:Master
                    Frequency:2.437 GHz (Channel 6)
                    Quality=11/70  Signal level=-84 dBm  Noise level=-95 dBm
                    Encryption key:on
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
                              24 Mb/s; 36 Mb/s; 54 Mb/s; 6 Mb/s; 9 Mb/s
                              12 Mb/s; 48 Mb/s
                    Extra:bcn_int=100


anupamsr 04-03-2008 09:20 AM

Something like this:
Code:

$ ESSID=(`grep ESSID: filename|sed -e 's/ //g'|cut -c7-|xargs`)
$ echo $ESSID[1]
Home


tallmtt 04-03-2008 10:37 AM

Thanks for your quick reply. That lists the available networks, but I want to be able to somehow associate the ESSID with its specific AP, key (off or on), and signal strength.

Maybe breaking up the file into separate temporary files in /tmp/ with that info? maybe awk array? I don't know how todo either and am quite a novice at scripting.

Thanks again for your help.

unSpawn 04-03-2008 11:39 AM

Probably way convoluted but with
Code:

#!/bin/sh
retVal() { case "${l[0]}" in Ce*) echo -en "${l[4]} ";; ES*|Fr*) echo -en "${l[0]//*:/} ";;
Q*) echo -en "${l[0]//*=/} ";; Encry*) echo ${l[1]//*:/};; *) continue;; esac; }
iwlist ath0 scanning|awk '/(Cell|ESS|Freq|Qual|Encry)/ {print}'|while read line; do
l=(${line}); retVal; done; exit 0

you don't need a temp file, it gets you the output as space separated values on one line per AP, so you can pack that output per line in arrays to work on.
Here's some links to BaSH scripting guides: http://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html, http://www.tldp.org/LDP/Bash-Beginne...tml/index.html (and http://www.tldp.org/LDP/abs/html/).

anupamsr 04-03-2008 11:53 AM

I am blind.

May be one day I will have vision.

unSpawn 04-03-2008 12:33 PM

Quote:

Originally Posted by anupamsr (Post 3109647)
I am blind.

Yeah, you're right. It's an abomination. This should look "better":
Code:

iwlist ath0 scanning| awk '/Cell/ {print $5}; /ESS/ {print substr($1,7)}; /Freq/ \
{print substr($1,11)}; /Qual/ {print substr($1,9)}; /Encr/ {print substr($2,5)}'


osor 04-03-2008 01:15 PM

Quote:

Originally Posted by unSpawn (Post 3109676)
This should look "better"

How about this:
Code:

iwlist ath0 scanning | awk -F '[ :=]+' '/(ESS|Freq|Qual)/{ printf $3" " }
/Encr/{ print $4 }'

Of course if the ESSID is something like "My Encrypted AP" you are in trouble.

tallmtt 04-03-2008 05:40 PM

You all are great! This command outputs:
Code:

# iwlist ath0 scanning | awk -F '[ :=]+' '/(ESS|Freq|Qual)/{ printf $3" " } /Encr/{ print $4 }'

"Home" 2.437 39/70 off
"linksys" 2.437 12/70 on
"NETGEAR" 2.462 4/70 off
"linksys" 2.437 7/70 off

Can someone give me an explanation of the command?

Thanks for your help - this gives me the setup I need to make an associative array in awk.

My next step is to make each line a field in the array. I will work on this tomorrow and if I need help will post that as well.

Any suggestions are always welcome.

osor 04-04-2008 01:20 PM

Quote:

Originally Posted by tallmtt (Post 3109911)
Can someone give me an explanation of the command?

Yes. The first part (-F '[ :=]+') sets your “field separator” to be one or more space, colon, or equal sign characters. The first command (/(ESS|Freq|Qual)/{ printf $3" " }) says that whenever awk encounters either ESS, Freq, or Qual, it will print the third field followed by a space (with no newline). The second command (/Encr/{ print $4 }) says that when awk encounters Encry, it will print the fourth field, followed by a newline. The result is that you get the output you want. If you wanted additionally to have the address printed out, you could add the command
Code:

/Cell/{printf substr($0,30)" "}
which means to print the entire line after the character at index 30 when awk encounters Cell.
Quote:

Originally Posted by tallmtt (Post 3109911)
Any suggestions are always welcome.

If all you need to do is sort the output, why not use the sort command. For example, suppose I had the following output:
Code:

# iwlist ath0 scanning | awk -F '[ :=]+' '/(ESS|Freq|Qual)/{ printf $3" " } /Encr/{ print $4 }'
"foo" 2.437 19/70 off
"bar" 2.437 9/70 on
"baz" 2.462 39/70 on
"qux" 2.437 56/70 off
"quux" 2.437 34/70 off

I want to sort this list first by the fourth field alphabetically (so off comes before on) and then by the third field numerically in descending order. So I could do:
Code:

# iwlist ath0 scanning | awk -F '[ :=]+' '/(ESS|Freq|Qual)/{ printf $3" " } /Encr/{ print $4 }' | sort -k4 -k3nr
"qux" 2.437 56/70 off
"quux" 2.437 34/70 off
"foo" 2.437 19/70 off
"baz" 2.462 39/70 on
"bar" 2.437 9/70 on

The above should work as long as the quality field is a fraction with denominator 70 (since sort only looks at the initial numerical part). If you want something that will be smart enough to tell that 70/100 is less than 69/70, you will probably want awk to print a decimal for you instead of the number itself.

godzillarama 12-09-2008 09:49 AM

Hello. I found this older thread by searching via Google and it has been a great help to me as I learn scripting. However, I must be missing something, because I still don't see how these examples make the results available as variables. I'd like to take the results and put them into an Xdialog menu so that the user could select which network to connect to, then pass the results to the iwconfig command based on the user's selection. I find that if I use iwconfig, I can connect more reliably than via wicd or WiFi Radar, neither of which seem to work very well in my configuation.

I've purchased some books on bash scripting, but I'm at a wall on the variable array technique. I'd appreciate any advice.

burschik 12-10-2008 12:18 AM

Well, if you can print out the information you need, you can also put it into variables, for instance by using "read":
Code:

print whatever | while read var1 var2 ...; do whatever; done

laho 08-15-2009 01:10 AM

I wish I searched for this thread instead of reinventing the wheel which took me weeks while holding a crying newborn. But it was great to learn the basics of awk and grep.

I am a recent migrant from Windows where I was using Netstumbler to align high gain antennas. I haven't found a simple tool in Linux that could provide a graphical feedback of signal level so I set to make my own script for this. I just need some direction, not asking anyone to write this for me.

For illustration the on-screen feedback would look something like this:

"MyWireless" 00:21:1E:41:E9:50 Channel:6 Signal Level -59 on
===================================================================

"Hotspot" 00:21:1E:41:E9:40 Channel:6 Signal Level -70 off
========================
...

The idea came from Wavemon except this one would show all non-associated APs.

I figured out how to make an animated bar and how to parse the output of 'iwlist scanning' and get the numerical values I need.

I am having trouble separating the iwlist output's cells so I can feed one number at a time to the part of the script that's doing the graphical bar feedback.

For example:
Code:

# extract Signal Level
iwlist wlan0 scanning | awk -F= '/Quality/ {print substr($3,1,3)}'

will return Signal Level values for all ESSIDs available at the given moment. But I need to filter them by the Address value so I can send only one number to be echoed as an animated bar (or histogram).

I haven't studied in detail how 'iwlist scanning' sorts out the cell output. They are not sorted by signal quality, level, etc. I am guessing that the order of cells may vary so simply filtering the output of the above code based on the order may not work. I think the solution I need has to be contained within the original awk line and tied to a unique identifier like Address.

Any tips are much appreciatted. What an amazing flexibility in Linux. I wish I had more time to play.

de55 04-14-2012 01:16 PM

Thanx for the oneliner, osor, the best approach I've found so far.

But, in my case, it outputs something like:

Code:

2.437 19/70 off
"foo" 2.437 9/70 on
"bar" 2.462 39/70 on
"baz" 2.437 56/70 off
"qux" 2.437 34/70 off
"quux"

So I came up with this (no problem with SSIDs with spaces, BSSIDs also printed):

Code:

iwlist ath0 scanning | awk -F '[ :=]+' '/Ad/{printf substr($0,30)" "} /(Channel:|Qual)/{printf $3" "} /Encr/{printf $4" "} /ESS/{print substr($0,27)}'
Not much experience with awk, would be nice to reorder fields, but without garbling oneliner...


All times are GMT -5. The time now is 06:24 AM.