read
has a parameter for timeout, you can use:
read -t 3 answer
If you want read
to wait for a single character (whole line + Enter is default), you can limit input to 1 char:
read -t 3 -n 1 answer
After proper input, return value will be 0, so you can check for it like this:
if [ $? == 0 ]; then
echo "Your answer is: $answer"
else
echo "Can't wait anymore!"
fi
I guess there is no need to implement background jobs in your situation, but if you want to, here is an example:
#!/bin/bash
function ProcessA() {
sleep 1 # do some thing
echo 'A is done'
}
function ProcessB() {
sleep 2 # do some other thing
echo 'B is done'
}
echo "Starting background jobs..."
ProcessA & # spawn process "A"
pid_a=$! # get its PID
ProcessB & # spawn process "B"
pid_b=$! # get its PID too
echo "Waiting... ($pid_a, $pid_b)"
wait # wait for all children to finish
echo 'All done.'
What you are missing is that most terminal descriptions (linux
is in the minority here, owing to the pervasive use of hard-coded strings in .inputrc
) use application mode for special keys. That makes cursor-keys as shown by tput
and infocmp
differ from what your (uninitialized) terminal sends. curses applications always initialize the terminal, and the terminal data base is used for that purpose.
dialog
has its uses, but does not directly address this question. On the other hand, it is cumbersome (technically doable, rarely done) to provide a bash-only solution. Generally we use other languages to do this.
The problem with reading special keys is that they often are multiple bytes, including awkward characters such as escape and ~. You can do this with bash, but then you have to solve the problem of portably determining what special key this was.
dialog
both handles input of special keys and takes over (temporarily) your display. If you really want a simple command-line program, that isn't dialog
.
Here is a simple program in C which reads a special key and prints it in printable (and portable) form:
#include <curses.h>
int
main(void)
{
int ch;
const char *result;
char buffer[80];
filter();
newterm(NULL, stderr, stdin);
keypad(stdscr, TRUE);
noecho();
cbreak();
ch = getch();
if ((result = keyname(ch)) == 0) {
/* ncurses does the whole thing, other implementations need this */
if ((result = unctrl((chtype)ch)) == 0) {
sprintf(buffer, "%#x", ch);
result = buffer;
}
}
endwin();
printf("%s\n", result);
return 0;
}
Supposing this were called tgetch
, you would use it in your script like this:
case $(tgetch 2>/dev/null) in
KEY_UP)
echo "got cursor-up"
;;
KEY_BACKSPACE|"^H")
echo "got backspace"
;;
esac
Further reading:
Best Answer
From
help read
:So try:
The
holder
variable is used since a variable loses its contents when used withread
unless it is readonly (in which case it's not useful anyway), even ifread
timed out:I couldn't find any way to prevent this.