0

I'm trying to figure out the best way to halt a running script using a keyboard shortcut while the terminal is not the active window.

This led me to learn about watching keyboard events with cat /dev/input/eventX ( where X is a number that corresponds to keystroke events)

I then learned about a tool evtest that will run until interrupted printing out the events (keystrokes) as they occur in a human readable format.

Here is the script I've managed so far, but its not working as expected. In a perfect solution the user could press Key_Space at anytime to halt the script, but I don't think that's possible here. So my workaround is to give them a 2 second window at the begining of the loop.

#!/bin/bash                                                              
exitCase='*type 1 (EV_KEY), code 57 (KEY_SPACE)*'

while [ true ]  do
    evtest  /dev/input/eventX |  read -s -t 2  line 
    if [ "$line" = "$exitCase" ] 
    then
        echo caught event
        exit 0

    else           
        echo loop doing stuff
    fi
done

Problem is the script will run once without looping, is there a better way to do this? Or how can I adjust my script to loop until it sees input matching the exit case?

I think another potential problem is that a single keystroke will print out multiple lines so maybe i need a evtest /dev/input/eventX | while read line? But after trying I could only get it to loop on events, and not while waiting for them.

1 Answers1

1

Since the right hand side of your evtest | read line pipeline runs in a separate subshell (and therefore never sets line to anything useful), I would have expected that the test that you have would never be true, and that the script would run indefinitely. It may be that you have code in the script that you are not showing?

In any case, you don't need to read from evtest. Instead, you could use grep (this would also take care of the "potential problem" that you mention at the end):

#!/bin/sh

exitCase='*type 1 (EV_KEY), code 57 (KEY_SPACE)*'

while true; do
    if evtest /dev/input/eventX | grep -q -Fx -e "$exitCase"; then
        echo caught event
        break
    else           
        echo loop doing stuff
    fi
done

This would break out of the loop as soon as evtest produced a line that is exactly the same as $exitCase. The -q option to grep tells it to be quiet (we're only interested in the exit status), with -F we make sure that grep compares the $exitCase string as a string rather than as a regular expression, and with -x we require whole line matches (no substrings, as if the string was anchored at both start and end).

If you want to impose a timeout on the grep or evtest, you may use timeout from GNU coreutils.

Kusalananda
  • 333,661