I've got this command which displays packets received and sent on port 1700.

tcpdump -AUq port 1700

In the packet there is the string rxpk, but most of the packets don't have it. When the output contains this string I want some script (which flashes a led) to run.

tcpdump -AUq port 1700 | awk '/rxpk/ { print | "/path/to/blink_led 18" }'

But it appears that it only matches the first time an rxpk is found, subsequent occurences wont trigger the { ... }-part

Anybody an idea why? Or even an other approach to run a script when rxpk is received?

  • Does blink_led do something every time it reads a line of input, or does it do something once regardless of input? – Mark Plotnick Sep 22 '16 at 21:58
  • The blink_led has to be called everytime the string rxpk is printed by tcpdump. – stUrb Sep 23 '16 at 8:26

The reason that the LED blinks only once is that when you print to a pipe, the pipe remains open, so there is only one invocation of blink_led. If blink_led was to read its stdin for instructions then this wouldn't be a problem. If it fails to read stdin and exits, then awk will exit too.

The conventional way around this is to close() the pipe so the next invocation starts a fresh one:

tcpdump -Alq port 1700 | awk '
  BEGIN { mypipe="/path/to/blink_led 18"; }
  /rxpk/ { print | mypipe; close(mypipe); }'

system() is fine too, as suggested by @heemayl (and probably better if blink_led has no interest in reading stdin at all).

You'll notice I'm using -l instead of -U, -l flushes stdout to avoid pauses if the output you want is waiting in a stdio buffer (-U enables whole packet flushing when you use -w to write to a file).

  • Thanks! Is it also possible to match multiple packets and give the match to the script as an argument? eg /(rxpk|txpk|stat)/ don't know if the regexp is that versatile? – stUrb Sep 23 '16 at 11:11
  • You can use an ERE of /(rxpk|txpk|stat)/ as the awk pattern, but it won't tell you what it matched, you'll need to call match($0,/(rxpk|txpk|stat)/); print substr($0,RSTART,RLENGTH) from the { } block ,or instead of /../ use match(..) (though both will only show the first match, in case that's important). – mr.spuratic Sep 23 '16 at 14:37
  • There is also a command called ngrep (netgrep) which might be more suitable for the packet collection – Tim Fletcher Sep 23 '16 at 18:48

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.