sgohl
sgohl

Reputation: 412

process every line from command output in bash

From every line of nmap network scan output I want to store the hosts and their IPs in variables (for further use additionaly the "Host is up"-string):

The to be processed output from nmap looks like:

Nmap scan report for samplehostname.mynetwork (192.168.1.45)
Host is up (0.00047s latency).

thats my script so far:

#!/bin/bash

while IFS='' read -r line
do
  host=$(grep report|cut -f5 -d' ')
  ip=$(grep report|sed 's/^.*(//;s/)$//') 
  printf "Host:$host - IP:$ip"
done < <(nmap -sP 192.168.1.1/24)

The output makes something I do not understand. It puts the "Host:" at the very beginning, and then it puts "IP:" at the very end, while it completely omits the output of $ip.

The generated output of my script is:

Host:samplehostname1.mynetwork
samplehostname2.mynetwork
samplehostname3.mynetwork
samplehostname4.mynetwork
samplehostname5.mynetwork - IP:

In separate, the extraction of $host and $ip basically works (although there might a better solution for sure). I can either printf $host or $ip alone.

What's wrong with my script? Thanks!

Upvotes: 0

Views: 1347

Answers (2)

Farhad Farahi
Farhad Farahi

Reputation: 39267

Try this:

#!/bin/bash
while IFS='' read -r line
do
  if [[ $(echo $line | grep report) ]];then
    host=$(echo $line | cut -f5 -d' ')
    ip=$(echo $line | sed 's/^.*(//;s/)$//')
    echo "Host:$host - IP:$ip"
  fi
done < <(nmap -sP it-50)

Output:

Host:it-50 - IP:10.0.0.10

I added an if clause to skip unwanted lines.

Upvotes: 1

chepner
chepner

Reputation: 531035

Your two grep commands are reading from standard input, which they inherit from the loop, so they also read from nmap. read gets one line, the first grep consumes the rest, and the second grep exits immediately because standard input is closed. I suspect you meant to grep the contents of $line:

while IFS='' read -r line
do
  host=$(grep report <<< "$line" |cut -f5 -d' ')
  ip=$(grep report <<< "$line" |sed 's/^.*(//;s/)$//') 
  printf "Host:$host - IP:$ip"
done < <(nmap -sP 192.168.1.1/24)

However, this is inefficient and unnecessary. You can use bash's built-in regular expression support to extract the fields you want.

regex='Nmap scan report for (.*) \((.*)\)'
while IFS='' read -r line
do
  [[ $line =~ $regex ]] || continue
  host=${BASH_REMATCH[1]}
  ip=${BASH_REMATCH[2]}
  printf "Host:%s - IP:%s\n" "$host" "$ip"
done < <(nmap -sP 192.168.1.1/24)

Upvotes: 4

Related Questions