Jon8RFC
Jon8RFC

Reputation: 85

BASH: grep/awk/sed to extract variable data

UPDATE I need to clarify that Jon8RFC-LT and DOMAIN are also just generic examples of dynamic content, like the IP address and MAC address; nmblookup retrieves and displays entirely dynamic content based on the ip address. If awk is used, I need to have a way to pull 4 dynamic values from the nmblookup: IP, hostname/asset name, domain name, MAC address. Sorry for the confusion, I updated the code to make it more clear.

I have been searching and using my Linux book for a couple of days and cannot find what I need for awk/gawk/grep/egrep/sed (I think I need one or more of those, elegantly). In a bash script, I'm running:

su_nmblookup=$(nmblookup -A $ipaddress)

which returns

WARNING: The "idmap backend" option is deprecated
added interface eth0 ip=a07d::a07d:a07d:a07d:a07d%eth0 bcast=b57d::ffff:ffff:ffff:ffff%eth0 netmask=ffff:ffff:ffff:ffff::
added interface eth1 ip=b57d::b57d:b57d:b57d:b57d%eth1 bcast=a07d::ffff:ffff:ffff:ffff%eth1 netmask=ffff:ffff:ffff:ffff::
added interface eth0 ip=234.234.234.234 bcast=12.12.12.12 netmask=255.255.0.0
Socket opened.
 Looking up status of 123.123.123.123
    JON8RFC-LT <00> -         B <ACTIVE> 
    DOMAIN        <00> - <GROUP> B <ACTIVE> 
    JON8RFC-LT <20> -         B <ACTIVE> 
    DOMAIN        <1e> - <GROUP> B <ACTIVE> 

    MAC Address = 4F-A2-4F-A2-4F-A2

The best I've managed, is to chop it down with this code:

display=${su_nmblookup/#*Looking/\Looking}
Looking up status of 123.123.123.123
    JON8RFC-LT <00> -         B <ACTIVE> 
    DOMAIN        <00> - <GROUP> B <ACTIVE> 
    JON8RFC-LT <20> -         B <ACTIVE> 
    DOMAIN        <1e> - <GROUP> B <ACTIVE> 

    MAC Address = 4F-A2-4F-A2-4F-A2

However, what I'd like to know is how to return either of these cleaned up formats. I want to learn how the grep/awk/sed works with extracting data with these two examples, one with preserving the formatting, and one with just new lines. I had a hell of a time even getting the quoting/coding to work properly here because of the formatting and gt/lt symbols!

Looking up status of 123.123.123.123
    JON8RFC-LT
    DOMAIN
    4F-A2-4F-A2-4F-A2

OR, simply

JON8RFC-LT
DOMAIN
123.123.123.123
4F-A2-4F-A2-4F-A2

Thank you for your help!

Upvotes: 5

Views: 1916

Answers (3)

mklement0
mklement0

Reputation: 440679

An annotated awk solution that provides both output formats - prettied and raw - selectable by a variable:

# Set this to:
#  * 1 for a "pretty" display with header line and indentation
#  * 0 for printing the raw data items only.
pretty=1

awk -v pretty=$pretty '
    # Skip lines before "Looking up ..."
  !startRow && /Looking up status of / { startRow=NR; }
  !startRow { next }
    # Parse the lines of interest relative to the "Looking up ..." row.
  NR==startRow { ip=$5; header=$0; next } # IP address
  NR==startRow+1 { nm=$1; next }          # name, e.g.: "JON8RFC-LT"
  NR==startRow+2 { dm=$1; next }          # domain, e.g.: "DOMAIN"
  /MAC Address =/ { ma=$4; exit }         # MAC address, e.g.: "4F-A2-4F-A2-4F-A2"
  END {         # all relevant lines processed; output result
    if (pretty) # print with header and indentation
      { print header; print "\t" nm; print "\t" dm; print "\t" ma }
    else        # print raw data items only
      { print nm; print dm; print ip; print ma }
  }' <(nmblookup -A $ipaddress)

A few quick pointers:

  • -v pretty=$pretty defines an awk variable based on a shell variable; note how the awk program as a whole is enclosed in single quotes to prevent accidental shell expansions inside the awk program, which should be treated as its own world, separate from the shell.
  • !startRow: awk variables in a numeric/Boolean context default to 0/false if not yet defined, so this expression evaluates to false until startRow is set to a non-zero value.
  • /Looking up status of/ is a regex that is matched against the current input line; NR contains the current, 1-based row (line) number.
  • next skips remaining pattern/actions for the current line and proceeds to the next line.
  • NR==startRow is a pattern that evaluates to true if the current line's index matches the value stored in startRow
  • $1, for instance, represents the 1st field from the current line - by default, awk breaks lines into fields - starting with index 1 and the ending index stored in variable NF - based on whitespace.
  • END is a special pattern whose associated block is executed after all input lines have been processed; note that an exit command in a previous action still causes the END action to be processed.
  • <(...) is an instance of process substitution which provides the output from any command as a pseudo file.

Upvotes: 2

Digital Trauma
Digital Trauma

Reputation: 16016

I see you want a grep/awk/sed answer, but you may be interested to know what you need is possible purely with builtins:

unset results
declare -A results
while read; do
    case $REPLY in
        *'Looking up status of '*) ip="${REPLY##* }";;
        *'MAC Address = '*) mac="${REPLY##* }";;
        *'    '*) tmp="${REPLY#    }"; results[${tmp%% *}]=1 ;;
    esac
done < <(nmblookup -A $ipaddress)
printf "%s\n" ${!results[@]}
echo $ip
echo $mac

This script fragment may be placed in your existing script.

This script reads each line of input and applies a case switch to match the patterns you are interested in. Each pattern has its own set of commands to format the data you need. In the case of lines that begin with 4 spaces, we use a bash associative array to make sure we only get one of each of the JON8RFC-LT and DOMAIN lines.

Note associative arrays require 4.0 or more.

Upvotes: 3

a5hk
a5hk

Reputation: 7844

Assuming the output of nmblookup -A 123.123.123.123 is redirected to file input.txt

awk '/Looking up status of/ {print} /JON8RFC-LT/ {if(a!=1){print "\t"$1;a=1}} /DOMAIN/ {if(b!=1){print "\t"$1;b=1}} /MAC Address/ {print "\t"$4}' input.txt

Updated as Etan Reisner suggested to be shorter:

awk '/Looking up status of/ {print} /JON8RFC-LT/ && !a {print "\t"$1;a=1} /DOMAIN/ && !b {print "\t"$1;b=1} /MAC Address/ {print "\t"$4}' input.txt

output:

 Looking up status of 123.123.123.123
    JON8RFC-LT
    DOMAIN
    4F-A2-4F-A2-4F-A2

Updated for Dynamic content

awk '/Looking up status of/,/MAC Address/ {print; getline;print "\t"$1;getline;print "\t"$1;getline;getline;getline;getline;print "\t"$4;exit 0}' input.txt

Assumes on the two lines after line Looking up ... you want the first word. Then ignores three lines and then prints MAC address.

Upvotes: 4

Related Questions