How to implement a timer keypress in bash? - bash

Here's what will happen, a message is displayed with a specified time waiting for keypress, if no keypress then it will resume.
Example
"Press ESC to exit, otherwise you will die.. 3..2..1"
"Press 'x' to procrastinate and check email, read some blogs, facebook, twitter.. otherwise you will resume work for 12 hours.. 3..2..1"
This should be a really handy function. How do I create this functionality in bash?

Look on the bash man page for the "read" command and notice the "-t timeout" option. Something like this should get you started
for i in 3 2 1 ; do
read -p $i... -n 1 -t 1 a && break
done

Use the -t and -n options of the read bash builtin command, also do not forget -r and -s. (see the manual for details)
#!/bin/bash
timeout=3
echo -n "Press ESC to exit, otherwise you will die..."
while [ $timeout -gt 0 ]; do
echo -n " $timeout"
if read -n1 -t1 -r -s x; then
echo
exit 0
fi
let timeout--
done
echo

Related

bash read timeout from serial port

I'm trying something like Linux serial port listener and interpreter?
However, I want a timeout
#!/bin/bash
stty -F /dev/ttyUSB1 300 cs7 parenb -parodd
echo -n -e 'Sending '
echo -n -e "\x2F\x3F\x21\x0D\x0A">/dev/ttyUSB1
read LINE -r -t1 </dev/ttyUSB1
echo -n "Read "
echo $LINE
I'd like to continue if I do not get input; it just hangs.
(It is part of an input routine for reading a powermeter https://electronics.stackexchange.com/questions/305745/ir-data-from-landisgyr-e350)
Based on this answer, I think you can use the timeout function to get what you want.
You'll probably have to do a bit of formatting and redirect the file to stdout, like in this answer, so it would look like this :
LINE="$(timeout 1 cat /dev/ttyUSB1)"
echo -n "Read "
echo $LINE
You can also just use a combination of sleep and kill, like in here.

bash read -s not working when combined with -t?

I have a bash script problem. I am doing while loop and inside this while loop I would like to read with timeout and if input is "q" leave while loop, but I would like to hide input("q").
#!/bin/bash
while [[ "$input" != "q" ]]; do
read -s -t 0.1 -n 1 input
done
I know that -s is supose to hide that but when I combine it with -t 0.1 it doesn't work. Although -s combined with -n works. Is there any solution to this?

read builtin doesn't work with pipe

I'd like to ask user a confirmation to read from stdin (Display output [Y/n]). It works Ok if some arguments were provided, or no arguments were provided but there was some input. However, if some data was piped to the script, there's no confirmation.
#!/bin/bash
output_file=$(mktemp)
cleanup() {
rm -f "$output_file"
}
trap cleanup 0 1 2 3 15
if [ $# -gt 0 ]; then
while [ $# -gt 0 ]; do
echo "$1" >> "$output_file"
shift
done
else
while read -r line; do
echo "$line" >> "$output_file"
done
fi
while true; do
read -p "Display output? [Y/n]" response
if [ -z "$response" ]; then
break
fi
case $response in
[Yy]*) break;;
[Nn]*) exit;;
esac
done
less "$output_file"
What prevent read -p to work? What should be done to provide consistent behavior?
The read command reads input from standard in. If you have standard in fed from a pipe then read looks for its data from the pipe, not from your terminal.
On most platforms you can work around this by redirecting the read command's input directly from the tty device, as in:
read -p "Display output? [Y/n]" response </dev/tty
If the script read everything from standard input, what is the read -p going to get? And it likely doesn't prompt if the input is not an 'interactive device' (aka terminal). Have you checked the Bash man page for read? It says:
-pprompt
Display prompt, without a trailing newline, before attempting to read any input. The prompt is displayed only if input is coming from a terminal.
When your input is from a pipe, it is not from a terminal.

Press any key with timeout progress displayed in shell

I want to provide user with a prompt to press any key or wait for a timeout to continue using shell. Usually this case is solved with following idiom:
read -rs -t3 -n1 "Press any key or wait to continue ..."
However this prompt seems a little bit clumsy to me and I would like to left only "Press any key to continue ..." part of a message and indicate timeout with dots printed each second. So I write following script:
#!/bin/sh
echo -n "Press any key to continue";
for _ in `seq 3`; do
if ! read -rs -n1 -t1 ; then echo -n "."; else break; fi
done
echo
It works just as I expect, but obviously there is too much code, so I have to put in separate file instead of using as sh -c "..." in script. Is there a way to implement it in more concise and compact way?
P.S. Returning non-zero error code on Ctrl-C pressed is a must.
A bit more concise :
echo -n "Press any key to continue";
for _ in {1..3}; do read -rs -n1 -t1 || printf ".";done;echo

Execute a command in a script and kill it when pressing a key

I want to write a bash script which records my voice until I press a concrete key. I have thought I could use this command
arecord -D hw -q -f cd -r 16000 speech.wav
which records from my laptop microphone and stops when the process is killed, but I don't know how to write bash code to call the process and then kill it when I press a concrete key. Can you help me?
key="q"
arecord speech.wav &
pid=$!
while read -n1 char ; do
if [ "$char" = "$key" ] ; then
kill "$pid"
break
fi
done
$! notation is the pid of last background job. the read builtin has the -n switch, with this switch only a number of characters instead of a full line is read at once.

Resources