This doesn't work on a lot of levels. Chiefly, bash isn't really good for multi-threaded programming. But if you're going to do it this way, you have to realize two things: (1) in order for your key-read "thread" to work, it has to have exclusive access to the tty. (2) When you put a process in the background, it will naturally copy stdin from the current process' tty. (3) Usually the shell will detect this and stop the background process.
Only foreground processes are allowed to read from or, if the user so specifies with stty tostop, write to the terminal. Background processes which attempt to read from (write to when stty tostop is in effect) the terminal are sent a SIGTTIN (SIGTTOU) signal by the kernel's terminal driver, which, unless caught, suspends the process.
You can see that here:
otheus@otheus-VirtualBox ~ $ ( while true; read x; do echo $x; done; ) &
otheus@otheus-VirtualBox ~ $
+ Stopped ( while true; read x; do
So the tty-reading process should be in the foreground. The background can do the "work", but make sure you close stdin first:
To stop the "worker" process, you will have to know its pid. To do that, you need to enable job-control within a script (it's off by default).
set -m does this. Start it and kill
%- after the keypress. You may want to make sure the keypress loop ends when the worker does. You do your key-monitor thread:
while jobs %- &>/dev/null; do
read -n 1 -s -t 1 key
# test key
if [[ $key == q ]]; then
kill -1 %-
The while condition tests if the job is still running/recognized. Once it ends, jobs will return false, and the loop exits. The read command now additionally times out after 1 second. Finally, after the loop exits, do a wait to make sure the job is "cleaned up". (If you have other jobs running, that will hang here.)
The other thing is: what you're trying to accomplish is inherently dangerous. Mixing root access and bash scripting is dangerous. There are some topics to address here, such as what happens when the user hits Control-C or Ctl-Z.
Lastly, I'm not even sure you can mix the worker thread with
su as in your example. When su runs, it will change the current tty to root, preventing your worker thread from outputting to it.