2

I have a Linux machine with BusyBox, which has a directory called /data/var/lib/connman.  That directory holds some directories that I'm not interested in.  But it contains many .config files that have a file name pattern like "wifi_<HASH1>_<HASH2>_managed_psk.config".  The file name in my example contains the interesting hash part, <HASH1>_<HASH2>, which are alphanumeric characters.  Examples of the full file names are:

  • "wifi_ff001122334_567890123456_managed_psk.config"
  • "wifi_778899ad_112233445566_managed_none.config"

Then each file is a text file and if it contains a line I'm interested in:

Name = <SSID>

The interesting part is <SSID>.

Real examples of that line are:

Name = MySSID
Name = r23$f"§F §"fsdfSdf

Now I want to get all the hashes from the file names together with their value of <SSID>, like this:

<HASH> : <SSID>

That's my desired output:

MySSID : 01abcd89
MyOtherSSID : ff001122334455,
r23öf"§F§"fsdfSdf : 7876543ad

So we need to grab the hash part from the file name and at the same time look at the file's content that comes after "Name =".

I've played around with a combination of grep and awk but never got the desired output.

What command can I use to achieve that?

2
  • 2
    1) You wrote " like this: <HASH> : <SSID>..." . Your sample output looks more like <SSID> : <HASH> . 2) are the Real Examples of <SSID> sample data from two different files, or both in one file? 3) if you're not going to use the <HASH2> from the file name, you can simplify your problem description by removing that info. (replace in filehame with _otherstuff?)` 4) The awk programing language is one tool that you can consider using. See Awk Tutorial and note the FILENAME variable as well as $1, $2, $3, .... $NF etc. ...
    – shellter
    Commented Mar 15 at 16:22
  • 3
    Update your question with your best attempt to solve the problem and readers will help you improve your understanding. Good luck.
    – shellter
    Commented Mar 15 at 16:22

2 Answers 2

0

Using Raku (formerly known as Perl_6)

~$ raku -e 'for dir(test => / \.config $/ ) -> $fh {
                put join " : ",
                    $_.split(/ \s* \= \s* /)[1],
                    $fh.match(/ <?after wifi_ > .*? <?before _managed > /)
                for $fh.lines.grep(/^Name/)
             };'

This solution uses Raku, a member of the Perl-family of programming languages. The code above relies on Raku's dir() and grep() routines, and therefore may be useful on platforms where classic shell-mediated file-globbing is absent/restricted (see SO discussion here).

Briefly, raku is called with the -e option, which tells Raku's compiler (Rakudo) to compile and execute the given one-liner program. The dir() method is called with the for keyword which tells Raku to loop through the filename values obtained using the filter test => / \.config $/. Individual resultant filenames are assigned to the temporary variable $fh and iterated through inside the block.

  • Once inside the block (reading from right-to-left), $fh.lines.grep(/^Name/) each filehandle is analyzed linewise for the presence of lines starting with the text "Name". If found Raku automatically assigns that line to $_ the topic variable, which is then split on whitespace/equal-sign, and the .[1] second-element (SSID value) is isolated.

  • The $fh filename is also massaged into final format, isolating .*? zero-or-more characters <?after wifi_ > after the text "wifi_" and <?before _managed > before the text "_managed".

  • The resultant output is joined on the requested : whitespace/colon, with first the filename-fragment followed by the SSID-value.

Sample Input (pwd):

~$ ls *.config
wifi_778899ad_112233445566_managed_none.config      wifi_ff001122334_567890123456_managed_psk.config

~$ cat wifi_778899ad_112233445566_managed_none.config
Name : SSIDabcd
junk
Name : SSIDefgh

~$ cat wifi_ff001122334_567890123456_managed_psk.config
Name : SSID1234
junk
Name : SSID5678

Sample Output:

SSIDabcd : 778899ad_112233445566
SSIDefgh : 778899ad_112233445566
SSID1234 : ff001122334_567890123456
SSID5678 : ff001122334_567890123456

Note, isolating the filename-text fragment above with match relies on Raku's new idiom for lookaheads/lookbehinds. If you'd rather use Raku's <()> "capture-markers", that match operation can be instead written:

$fh.match(/ wifi_ <( .*? )> _managed /)

https://docs.raku.org/routine/dir
https://docs.raku.org/routine/grep
https://raku.org

0

As the system is using busybox, I assume it won't have things like perl. busybox has a very capable awk implementation though, so you should be able to do:

find . -name '*_*_*_*.config' -type f -exec awk '
  match($0, /^[[:blank:]]*Name[[:blank:]]*=[[:blank:]]*[^[:blank:]]/) {
    ssid = substr($0, RLENGTH)
    sub(/[[:blank:]]+$/, "", ssid)
    base = FILENAME
    sub(".*/", "", base)
    if (match(base, "_[[:xdigit:]]+_[[:xdigit:]]+_"))
      print ssid, substr(base, RSTART+1, RLENGTH-2)
    nextfile
  }' {} +

If your busybox was built without support for find -exec {} +, you can replace the + with ';', that will just be less efficient.

If it was built without support for POSIX character classes in awk, you can replace [[:blank:]] with [ \t] and [[:xdigit:]] with [0-9a-fA-F].

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .