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.
Advertisement
Answer
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.