7

I used to have this command to count how many times I have click with a mouse, the command is xev | grep "ButtonPress".

my colleague modify the command so that it return:

ButtonPress 0
ButtonPress 1
ButtonPress 2
ButtonPress 3

and so on... Unfortunately he's no longer contactable so I can't reach him anymore.

I recall the involvement of i++ and something like that, how to reproduce the command?

1 Answers1

11

The fact that there's i++ suggests there was either bash or ksh shell in use,potentially awk or perl as well. In either case, we can use process substitution <(...) to feed output of xev to counting loop (although simple pipeline xev | while... could work just fine).

text processing tools:

Portably and for fewer key strokes we can use awk :

$ xev | awk '/ButtonPress/{print "ButtonPress",i++}'
ButtonPress 0
ButtonPress 1
ButtonPress 2
ButtonPress 3

perl version:

$ xev | perl -ne '/ButtonPress/ && printf("ButtonPress:%d\n",++$i)'
ButtonPress:1
ButtonPress:2
ButtonPress:3

Shells:

Here's what works in bash:

$ i=0; while IFS= read -r line; do [[ $line =~ ButtonPress ]] && { ((i++)); printf 'ButtonPress: %d\n' "$i";} ;done < <(xev)
ButtonPress: 1
ButtonPress: 2
ButtonPress: 3

In case you don't want spammy output of many lines, we can use printf to send control code to clear previous line and output only the running count (that is you'd only see integer value change on the line):

$ i=0; while IFS= read -r line; do [[ $line =~ ButtonPress ]] && { ((i++)); printf "\r%b" "\033[2K"; printf 'ButtonPress: %d' "$i";} ;done < <(xev)

Portably in POSIX shell:

$ xev | ( i=0; while IFS= read -r l; do case "$l" in  *ButtonPress*) i=$((i+1)) && printf 'ButtonPress:%d\n' "$i";;  esac ;done)
ButtonPress:1
ButtonPress:2
ButtonPress:3

basic utils:

For simple, quick, and dirty way we can hack this via cat -n with line count being printed on the left instead of right:

$ xev | grep --line-buffered 'ButtonPress' | cat -n
     1  ButtonPress event, serial 34, synthetic NO, window 0x4a00001,
     2  ButtonPress event, serial 34, synthetic NO, window 0x4a00001,
     3  ButtonPress event, serial 34, synthetic NO, window 0x4a00001,
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • I tried your first command that has awk in it, it works but there's a bit of lag when the output return – Jackie Nelson Mar 07 '19 at 09:53
  • However, your second and third command works perfectly, thanks a lot Sergiy – Jackie Nelson Mar 07 '19 at 09:53
  • @JackieNelson A bit of lag might suggest buffering, which may be related to another awk version in use. Recent Ubuntu uses gawk and before 16.04 default was mawk IIRC. Regardless, glad I could help :) – Sergiy Kolodyazhnyy Mar 07 '19 at 09:56
  • Can you make so that the number start from one on perl version ? Not zero – Jackie Nelson Mar 07 '19 at 09:57
  • @JackieNelson Yep, already changed that – Sergiy Kolodyazhnyy Mar 07 '19 at 10:02
  • I prefer a shorter version, so the update is helpful. Thanks ! By the way I don't see any difference with Perl command, so how do you make it start from one ? Just curious – Jackie Nelson Mar 07 '19 at 10:10
  • @JackieNelson Difference is $i++ in original and ++$i in changed command. $i++ is post increment - increment variable after assigning value to variable. ++$i is pre-increment - increment variable first then assign to variable. This type of semantic is used most notably in C language and many others. Python has it too, but it's a bit more involved there :) – Sergiy Kolodyazhnyy Mar 07 '19 at 10:13
  • The same works in awk and bash as well: xev | awk '/ButtonP/{print $1,++i}' and i=0; while IFS= read -r line; do [[ $line =~ ButtonPress ]] && { printf '%s %d\n' "${line%% *}" "$((++i))";} ;done < <(xev) – dessert Mar 07 '19 at 12:08