Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is there any way to count the lines of a non-terminating input source? For example, I want to run the following for a period of time to count the number of requests:

ngrep -W byline port 80 and dst host 1.2.3.4 | grep ":80" | wc

Obviously, that doesn't work. When I Ctrl+C kill that, I'm not going to get any output from wc. I would rather avoid creating a file if I can.

share|improve this question
    
Just a reminder, that since it’s a stream sed -n '$=' may be faster than wc on large data. –  tijagi Sep 3 at 18:28

4 Answers 4

up vote 4 down vote accepted

Typing Ctrl+C from the terminal sends SIGINT to the foreground process group. If you want wc to survive this event and produce output, you need to have it ignore the signal.

The solution is to run wc in a subshell and have its parent shell set SIGINT to be ignored before running wc. wc will inherit this setting and not die when SIGINT is sent to the process group. The rest of the pipeline will die, leaving wc reading from a pipe that has no process on the other end. This will cause wc to see EOF on the pipe and it will then output its counts and exit.

ngrep -W byline port 80 and dst host 1.2.3.4 | grep ":80" | (trap '' INT ; wc)
share|improve this answer
2  
You may want to include grep in that subshell or add the --line-buffered option (if GNU grep). Otherwise, you wont count the lines stored in grep's output buffer that have not been flushed yet by the time of the CTRL-C. –  Stéphane Chazelas Sep 3 at 21:12

Here is how you can keep counting afer reading the current count:

My non-terminating test input source is a ping:

$ ping 127.0.0.1  
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.028 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.025 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.045 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.032 ms
64 bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.030 ms
^C

With other solutions, we had to decide when to read out the line count, and were interrupting the running command.
But ideally we would just like to know the current line count, right?

So, why not just count the lines? The right tool for the job is nl, adding the current count in front of each line:

$ ping 127.0.0.1 | nl
     1  PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
     2  64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.040 ms
     3  64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.022 ms
     4  64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.025 ms
     5  64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.021 ms
     6  64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.022 ms
     7  64 bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.022 ms
     8  64 bytes from 127.0.0.1: icmp_seq=7 ttl=64 time=0.021 ms
     9  64 bytes from 127.0.0.1: icmp_seq=8 ttl=64 time=0.029 ms
^C
share|improve this answer

You can use:

$ ngrep -W byline port 80 and dst host 1.2.3.4 | grep ":80" |
perl -nle 'system("clear");print $.'

perl will keep track what lines you had, clear old output before print it.

share|improve this answer

If you’re willing to specify a time limit (rather than just doing it off the cuff), you could use this trick

( cmdpid=$BASHPID; (sleep 300; kill $cmdpid) & exec ngrep (ngrep args) ) | grep ":80" | wc

inspired by this answer to a recent question over on SU; essentially How to stop a running program after 5 minutes and continue?

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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