3

Currently I'm using netstat for this:

if netstat -an | grep ESTABLISHED | grep $address:$port > /dev/null; then
    # command
fi  

Is there a more elegant solution?

3

As far as elegance is concerned, I'd modify two things in your command:

  • As mentioned in comment by Chris, you can use -q instead of output redirection.
  • Use one grep instead of two:

    if netstat -an | grep -q " $address:$port .* ESTABLISHED"; then
    
  • I advice not using grep, when there's no need in regexps fgrep fits better. – poige Apr 13 '12 at 4:48
  • 1
    @poige But here you do have a regexp. And using fgrep (or rather grep -F, since fgrep is deprecated) in this case is useless also due to negligible potential speed benefit in a single invocation. It would take far more time to type a (longer) working filter with fgrep - and it would need to use pipe, just as in the OP's example. – rozcietrzewiacz Apr 13 '12 at 6:40
  • My bad, I've overlooked it. Regarding fgrep: 1) GNU's man can call it deprecated (whatever), but neither does BSD's or Solaris'. So I don't care typing extra -f to grep, neither advice doing that to anyone. :) – poige Apr 14 '12 at 16:27
  • 2
    2) Lots of people tend blindly use grep and spending theirs time in escaping its spec. symbols, or what's a way worse, getting wrong results having forgotten to escape such symbs.. Look, $address you've used in your grep actually has that spec. symbs. — dots. That's a flaw, actually. – poige Apr 14 '12 at 16:27
  • 1
    Not only at the beginning, there's a port as well where, say :80 would match ":80anything" — that's why I support solution using ss. And yeah, when there's terminator like :, dots can be safe. But otherwise 192.168.1.4 perfectly matches the whole 192.168.104, for e. g.. – poige Apr 15 '12 at 4:27
2

lsof should do the job. Ask it to give you machine-parseable output with the -F option.

lsof -n -i @${hostname}:${port} -F nT | grep '^TST=ESTABLISHED$'

If you need more information:

lsof -n -i -F nT | awk '
    function host_port(s, a) {
        match(s, /:[^:]*$/);
        a["host"] = substr(s, 1, RSTART-1);
        a["port"] = substr(s, RSTART+1);
    }
    sub(/^p/,"") {pid = $0}
    sub(/^n/,"") {
        split($0, endpoints, "->");
        host_port(endpoints[1], from);
        host_port(endpoints[2], to);
    }
    /^TST=ESTABLISHED$/ {
        print "Established from", from["host"] ":" from["port"],
              "to", to["host"] ":" to["port"]
    }
'
2

with ss:

if ss -n -o state established '( dport = $hostname:$portnumber )'|awk 'NR==2{exit 0}END{exit 1}';then 
1

That works well enough for now, for Linux.

On other UNIX systems (the ones I have my hands on are Mac OS X and Solaris) the port is separated by . instead of :.

And this will most likely fail for any IPv6 connection. netstat truncates IPv6 addresses, so make sure to use --wide. But again, that's not a portable option.

1

You can use lsof instead of netstat: something like this: sudo /usr/sbin/lsof -i tcp@1.2.3.4:80, but lsof is only available for root user and often not installed by default, so it's additional external dependency.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.