Warm tip: This article is reproduced from serverfault.com, please click

awk if not matched print "unknown", multiple matches

发布于 2020-11-29 20:08:10

I am getting an nmap result and I am trying to process various (host up or down) results using awk.

I am passing an ip address and I am trying to get the following: status (up or down), host name, OS.
GOAL: I need to have an access to every field to be able to update the database with its value. Also I am trying to accomplish that in as simple as possible way, maybe there is any way to save field in a variable so then I can use it, check if it's empty etc.?

More into details:

  1. if Host is down host_name="unknown", and OS="unknown"
  2. if Host up grab the host_name and check OS -> two possibilities here, either /Running:/ or /OS guesses/ both of them will give us the OS, but we will have either one or another.

Expected output of host that is up:

                     $ip              $status     $host_name    $os
when host up:        134.99.120.2     host_up     HostName      Linux
when host down:      134.99.120.2     host_down   unknown       unknown

I came up with this one liner here:
sudo nmap -O -R -p 22 -oN -T4 134.99.120.2 | awk '/down/{print$5}/Nmap scan report/{print$5}/Running:/{print$2}/OS guess/{print$4}'
But that does not provide any control over the output.

Raw Outputs from nmap:
When Host up:

 
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 14:58 EST
> Nmap scan report for HostName (134.99.120.2) Host is up (0.00067s
> latency). PORT   STATE SERVICE 22/tcp open  ssh Warning: OSScan
> results may be unreliable because we could not find at least 1 open
> and 1 closed port Device type: general purpose Running: Linux OS CPE:
> xx:/o:xxx:xxxxxos:9.10 OS details: Linux Network Distance: 7 hops OS
> detection performed. Please report any incorrect results at
> http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned
> in 2.58 seconds 

When host down:

> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 15:00 EST
> Note: Host seems down. If it is really up, but blocking our ping
> probes, try -Pn Nmap done: 1 IP address (0 hosts up) scanned in 3.64
> seconds 
Questioner
dwt.bar
Viewed
0
markp-fuso 2020-11-30 06:46:50

NOTE Looks like Raman was a bit faster on the 'Post Your Answer' button ...

Assumptions:

  • nmap output will always be like one of the two examples provided by OP
  • nmap output will always have the Hostname and OS name in the same fields (ie, don't have to worry about nmap wrapping lines at different words due to variable lengths of data)
  • while the OP shows OS guess in their sample awk, the sample nmap data shows OS details (answer - below - is based on OS details; OP can modify per what their nmap call actually returns)
  • nmap data does in fact include a > in the first column of every line of output (as displayed in OPs sample inputs); this means OPs awk field references may need to shift +/- accordingly (OP can adjust answer - below - based on whether or not a line starts with >)

Sample inputs (in lieu of running nmap on my host):

$ cat nmap.up.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 14:58 EST
> Nmap scan report for HostName (134.99.120.2) Host is up (0.00067s
> latency). PORT   STATE SERVICE 22/tcp open  ssh Warning: OSScan
> results may be unreliable because we could not find at least 1 open
> and 1 closed port Device type: general purpose Running: Linux OS CPE:
> xx:/o:xxx:xxxxxos:9.10 OS details: Linux Network Distance: 7 hops OS
> detection performed. Please report any incorrect results at
> http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned
> in 2.58 seconds

$ cat nmap.down.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 15:00 EST
> Note: Host seems down. If it is really up, but blocking our ping
> probes, try -Pn Nmap done: 1 IP address (0 hosts up) scanned in 3.64
> seconds

One awk solution, though I'm assuming OP won't actually have 2 sets of nmap output for a single ip address (???) ...

ipaddr='134.99.120.2'

awk -v ip="${ipaddr}" '                                # pass ip addr in as awk variable "ip"
FNR==1            { hstat="host_up"                    # reset defaults for status ...
                    hname=hos="unknown"                # hostname and host OS
                  }
/down/            { hstat="host_down" ; next }         # reset status
/scan report for/ { hname=$6          ; next }         # reset hostname
/OS details/      { hos=$5            ; next }         # reset host OS

ENDFILE           { fmt="%-18s%-12s%-15s%s\n"          # re-usable format
                    if ( NR==FNR )                     # for first file print a header:
                       { printf fmt, "$ip", "$status", "$host_name", "$os" }

                    printf fmt, ip, hstat, hname, hos  # otherwise print results
                  }
' nmap.up.dat nmap.down.dat

NOTE: ENDFILE requires GNU awk (per Ed Morton's comment)

The above generates:

$ip               $status     $host_name     $os
134.99.120.2      host_up     HostName       Linux
134.99.120.2      host_down   unknown        unknown