Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to grep listening on port 80 that can also filter other port contain 80 such as 8080 8088 ...?

Tags:

linux

grep

bash

I want to use bash to grep if any process is listening on port 80,but now I stumble upon other port number which annoys me. How can I filter this in grep?

netstat -ant|grep LISTEN|grep 80|wc -l

It also outputs other records such as 8080 8088 and so on.

like image 348
clevertension Avatar asked May 17 '12 01:05

clevertension


4 Answers

I'm looking at the output of my netstat command, and see this:

tcp4       0      0  10.0.1.10.56941        64.34.119.101.80       ESTABLISHED
tcp4       0      0  10.0.1.10.56936        64.34.119.101.80       ESTABLISHED
tcp4       0      0  10.0.1.10.56932        64.34.119.101.80       ESTABLISHED
tcp4       0      0  10.0.1.10.56929        64.34.119.101.80       ESTABLISHED
tcp4       0      0  10.0.1.10.56922        64.34.119.101.80       ESTABLISHED
tcp4       0      0  10.0.1.10.56914        64.34.119.101.80       ESTABLISHED
tcp4       0      0  *.*                    *.*                    CLOSED     
tcp46      0      0  *.80                   *.*                    LISTEN     
tcp4       0      0  127.0.0.1.49153        *.*                    LISTEN     
tcp4       0      0  127.0.0.1.49152        *.*                    LISTEN     
tcp4       0      0  *.631                  *.*                    LISTEN     
tcp6       0      0  *.631                  *.*                    LISTEN     

I take it that the port is the last number in the five part dotted output. That means that

grep "\.80 " 

will pick up only port 80. The \. says to pick up the period. (Normally the period means any character in regular expressions). And, by putting a space after the 80, you'll guarantee that you're not going to pick up port 8080. In fact, you're guaranteed that you're not going to pick up IP addresses that have .80 in them.

In fact, I'd recommend to use awk instead of grep. With awk, you can specify fields and do a bit more processing:

$ netstat -ant | awk '$6 == "LISTEN" && $4 ~ /\.80$/' | wc -l

With awk each column automatically becomes a separate field. Field #6 ($6 in awk) is the one that says ESTABLISHED, CLOSED, LISTEN in it. Field $4 is the first column IP address one.

In the above, I'm looking for lines that have the word LISTEN in the sixth field, and where field #4 matches the regular expression \.80$. The $ is an anchor to the end of the string, and the \. is picking up a decimal point and not representing any character. The awk command automatically prints out each line that matches, so I don't have to specify that.

Awk is really a programming language. It assumes a read loop for each line in the file. You can have a BEGIN clause that gets executed before the file is read and an END clause that executes after the file has been read. The various fields are numbered and represented with a dollar sign. The special $0 variable represents the whole line. Special variables like like NF gives you the number of fields in a line and NR gives you the number of lines read in. You also have a whole slew of functions to help parse text, etc. Here's a full blown version of the awk script that basically lays out everything for you, and does its own line counting, so you don't have to pipe to wc -l.:

$ netstat -ant | awk '
      BEGIN {total = 0}
      END {print "There are " total " lines I found"}
      {
          if ($6 == "LISTEN" && $4 ~ /\.80$/) {
              total = total + 1
          }
      }'

Appendage

OP gets the following output:

tcp       0      0  0.0.0.0:8080        0.0.0.0:*       LISTEN

In this case, try either:

$ netstat -ant | awk '$6 == "LISTEN" && $4 ~ /:80$/' | wc -l

Where the \. is replaced by a : or...

$ netstat -ant | awk '$6 == "LISTEN" && $4 ~ /[\.:]80$/' | wc -l

Which uses [\.:] which will get it whether it's a colon or a period. Heck, might as well go all the way...

$ netstat -ant | awk '$6 == "LISTEN" && $4 ~ /[^0-9]80$/' | wc -l

The [^0-9] means not a numeric character. You can't go wrong with that. This way, whether it's a period, a colon, a semi-colon, a comma, or whatever separator your version of netstat uses, it will work.

like image 124
David W. Avatar answered Nov 16 '22 11:11

David W.


Instead of grepping the output of netstat -- asking for more information than you need and then discarding the bulk of it -- simply ask fuser which process has the port you care about open:

$ fuser -n tcp 4005
4005/tcp:            19339

If you only care to know if any process has the port in question open, you can do this even more quickly and efficiently, without needing to process output at all, by using the -q argument to fuser and operating on its exit status:

if fuser -q -n tcp 4005 ; then
    echo "port is in use"
else
    echo "port not in use"
fi

If you want to know how many connections there are to a remote port, fuser can do that too:

fuser -n tcp ,,80

...or connections to a remote port on a specific host:

fuser -n tcp ,1.2.3.4,80

In short -- using the right tool for the job to query for the parameters you want directly prevents you from needing to do text-based filtering in the first place.

like image 41
Charles Duffy Avatar answered Nov 16 '22 11:11

Charles Duffy


Use grep ":80 " instead of grep 80

like image 3
laher Avatar answered Nov 16 '22 11:11

laher


You can take advantage of the fact that ports are preceded by a colon (like :80). The fasting thing then would be something like:

netstat -ant | grep ':80\b.*LISTEN'

That way you're not invoking grep twice. Also, grep has the ability to count matches with -c, so you can use that instead of wc:

netstat -ant | grep -c ':80\b.*LISTEN'
like image 2
Tim Pote Avatar answered Nov 16 '22 11:11

Tim Pote