This may sound trivial, but I'm pretty sure this question hasn't been asked, or at least I can't find it.
I'm looking for a way to construct an infinite wait (not necessarily a loop) with shell scripting so that it waits forever and can be killed (or technically, to receive a SIGTERM
). The following are known possible constructs and arguments against them:
while true; do sleep 1; done
This almost gets it, but sincesleep
is an external command, when I send aSIGTERM
to the running script, it has to wait for thesleep
to finish first and then process the signal. Changesleep 1
to something likesleep 10
and the lag will be obvious. Also the solution wakes up the CPU every 1 second, which is not ideal.while true; do read; done
This is perfect whenstdin
is tty.read
is a shell builtin andSIGTERM
arrives at the script instantly. But, whenstdin
is/dev/null
, the script eats up all the CPU by helplessly runningread
forever on/dev/null
.
Thus a shell builtin construct that waits forever is required. Skimming through man dash
I didn't find such one - the only blocking builtins are read
and wait
, and I don't have idea how I can construct an ideal one using wait
.
The answer should be applicable to POSIX shell (effectively dash
), or less preferably, Bash.
Additional notes.
The situation where the first example doesn't work perfectly is more complex than I thought. With the following shell script:
#!/bin/sh
echo $$
while true; do
sleep 100
done
if you kill it at another tty, it terminates immediately. The funny thing begins when you attempt to do trapping. With this script:
#!/bin/sh
at_term() {
echo 'Terminated.'
exit 0
}
trap at_term TERM
echo $$
while true; do
sleep 20
done
What happens is exactly described in example 1. This happens with bash, dash and zsh. And it's under this condition that I'm seeking a "perfect" infinite look construct.
Here's a solution without a loop:
What's wrong with your 2nd option but forcing it to read from
stdin
? (Requiresbash
)From
man bash
you can use a named pipe for your read:
if you later want to send different arbitrary "signals" to the pipe, the read can be use in combination with a case statement to take appropriate actions (even useful ones)
If you have GNU coreutils, which accepts floating-point seconds, you can try:
This should block until the 64-bit timestamp wraparound.
SIGTERM sent to a process is delivered by the kernel to the process whether it is sleeping or not.
Try experimenting, maybe like this (bash example)