Eros
Eros

Reputation: 21

AWK taking action on a running output in bash

I need to use the output of a command, which is:

nmap -n -Pn -sS --vv <*IPs*>

The output of this command is devided into 2 parts; first a discovery and after that a port scan, both of them separated by the very first line that says

Nmap scan report for <FirstIP>

What I need is the output of this first part, which by the way is the fastest one, and I need to pipe it to a further command/s (awk, grep or whatever) to filter only the IP addresses. Obviously, the intention of doing this is the need of stopping the running command exactly when the line "Nmap scan report for <*FirstIP*>" appears on the shell (first, because I don't need the other part and second, because the other part takes too much time!)

I found a very close solution here but it didn't worked because it executes both commands (nmap and awk) but there's no output in stdout in shell.

I would be looking for something like this:

nmpa -n -Pn -sS --vv <*IPs*> | awk '/Not shown/ {system("pkill nmap")}' | awk '/^Discovered/{print $6}'

But obviously this doesn't work.

Any ideas?

Upvotes: 2

Views: 225

Answers (2)

Ed Morton
Ed Morton

Reputation: 203532

Given this command line:

left-side | right-side

The problems you have are:

  1. The shell will buffer the output of any command going to a pipe so you may not see "Not shown" in the right-side command until after the left-side command has finished running, and
  2. You want the left-side command to stop running as soon as the right-side command sees "Not shown"

For the first problem, use stdbuf or similar.

For the second - exiting the right-side command will send a terminate signal back to the left-side command so you don't need to do anything else, what you want to happen will simply happen when you exit the right-side command.

So your command line would be something like:

nmap -n -Pn -sS --vv <*IPs*> |
stdbuf awk '/Not shown/{exit} /^Discovered/{print $6}'

idk if you meant to use "Not shown" or "Nmap scan report for" in your sample code. Use whichever is the string you want awk to exit at.

Upvotes: 2

1337p337
1337p337

Reputation: 36

Most flavors of awk do buffering. There's no option to do what you're doing in gawk, but if you use mawk, you can give it the -Winteractive option, which does not buffer.

Incidentally, you are running two awks, but you only need one:

nmap -n -Pn -sS --vv <*IPs*> | mawk -Winteractive '/Not shown/ {system("pkill nmap")} /^Discovered/{print $6}'

Every predicate in awk runs the associated block. (Although I love awk, this use case might match expect better.)

Upvotes: 2

Related Questions