Bash: infinite sleep (infinite blocking)
Solution 1
sleep infinity
does exactly what it suggests and works without cat abuse.
Solution 2
tail
does not block
As always: For everything there is an answer which is short, easy to understand, easy to follow and completely wrong. Here tail -f /dev/null
falls into this category ;)
If you look at it with strace tail -f /dev/null
you will notice, that this solution is far from blocking! It's probably even worse than the sleep
solution in the question, as it uses (under Linux) precious resources like the inotify
system. Also other processes which write to /dev/null
make tail
loop. (On my Ubuntu64 16.10 this adds several 10 syscalls per second on an already busy system.)
The question was for a blocking command
Unfortunately, there is no such thing ..
Read: I do not know any way to archive this with the shell directly.
Everything (even sleep infinity
) can be interrupted by some signal. So if you want to be really sure it does not exceptionally return, it must run in a loop, like you already did for your sleep
. Please note, that (on Linux) /bin/sleep
apparently is capped at 24 days (have a look at strace sleep infinity
), hence the best you can do probably is:
while :; do sleep 2073600; done
(Note that I believe sleep
loops internally for higher values than 24 days, but this means: It is not blocking, it is very slowly looping. So why not move this loop to the outside?)
.. but you can come quite near with an unnamed fifo
You can create something which really blocks as long as there are no signals send to the process. Following uses bash 4
, 2 PIDs and 1 fifo
:
bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'
You can check that this really blocks with strace
if you like:
strace -ff bash -c '..see above..'
How this was constructed
read
blocks if there is no input data (see some other answers). However, the tty
(aka. stdin
) usually is not a good source, as it is closed when the user logs out. Also it might steal some input from the tty
. Not nice.
To make read
block, we need to wait for something like a fifo
which will never return anything. In bash 4
there is a command which can exactly provide us with such a fifo
: coproc
. If we also wait the blocking read
(which is our coproc
), we are done. Sadly this needs to keep open two PIDs and a fifo
.
Variant with a named fifo
If you do not bother using a named fifo
, you can do this as follows:
mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"
Not using a loop on the read is a bit sloppy, but you can reuse this fifo
as often as you like and make the read
s terminat using touch "$HOME/.pause.fifo"
(if there are more than a single read waiting, all are terminated at once).
Or use the Linux pause()
syscall
For the infinite blocking there is a Linux kernel call, called pause()
, which does what we want: Wait forever (until a signal arrives). However there is no userspace program for this (yet).
C
Create such a program is easy. Here is a snippet to create a very small Linux program called pause
which pauses indefinitely (needs diet
, gcc
etc.):
printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause
python
If you do not want to compile something yourself, but you have python
installed, you can use this under Linux:
python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'
(Note: Use exec python -c ...
to replace the current shell, this frees one PID. The solution can be improved with some IO redirection as well, freeing unused FDs. This is up to you.)
How this works (I think): ctypes.CDLL(None)
loads the standard C library and runs the pause()
function in it within some additional loop. Less efficient than the C version, but works.
My recommendation for you:
Stay at the looping sleep. It's easy to understand, very portable, and blocks most of the time.
Solution 3
Maybe this seems ugly, but why not just run cat
and let it wait for input forever?
Solution 4
TL;DR: sleep infinity
actually sleeps the maximum time allowed, which is finite.
Wondering why this is not documented anywhere, I bothered to read the sources from GNU coreutils and I found it executes roughly what follows:
- Use
strtod
from C stdlib on the first argument to convert 'infinity' to a double precision value. So, assuming IEEE 754 double precision the 64-bit positive infinity value is stored in theseconds
variable. - Invoke
xnanosleep(seconds)
(found in gnulib), this in turn invokesdtotimespec(seconds)
(also in gnulib) to convert fromdouble
tostruct timespec
. -
struct timespec
is just a pair of numbers: integer part (in seconds) and fractional part (in nanoseconds). Naïvely converting positive infinity to integer would result in undefined behaviour (see §6.3.1.4 from C standard), so instead it truncates toTYPE_MAXIMUM(time_t)
. - The actual value of
TYPE_MAXIMUM(time_t)
is not set in the standard (evensizeof(time_t)
isn't); so, for the sake of example let's pick x86-64 from a recent Linux kernel.
This is TIME_T_MAX
in the Linux kernel, which is defined (time.h
) as:
(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
Note that time_t
is __kernel_time_t
and time_t
is long
; the LP64 data model is used, so sizeof(long)
is 8 (64 bits).
Which results in: TIME_T_MAX = 9223372036854775807
.
That is: sleep infinite
results in an actual sleep time of 9223372036854775807 seconds (10^11 years). And for 32-bit linux systems (sizeof(long)
is 4 (32 bits)): 2147483647 seconds (68 years; see also year 2038 problem).
Edit: apparently the nanoseconds
function called is not directly the syscall, but an OS-dependent wrapper (also defined in gnulib).
There's an extra step as a result: for some systems where HAVE_BUG_BIG_NANOSLEEP
is true
the sleep is truncated to 24 days and then called in a loop. This is the case for some (or all?) Linux distros. Note that this wrapper may be not used if a configure-time test succeeds (source).
In particular, that would be 24 * 24 * 60 * 60 = 2073600 seconds
(plus 999999999 nanoseconds); but this is called in a loop in order to respect the specified total sleep time. Therefore the previous conclusions remain valid.
In conclusion, the resulting sleep time is not infinite but high enough for all practical purposes, even if the resulting actual time lapse is not portable; that depends on the OS and architecture.
To answer the original question, this is obviously good enough but if for some reason (a very resource-constrained system) you really want to avoid an useless extra countdown timer, I guess the most correct alternative is to use the cat
method described in other answers.
Edit: recent GNU coreutils versions will try to use the pause
syscall (if available) instead of looping. The previous argument is no longer valid when targeting these newer versions in Linux (and possibly BSD).
Portability
This is an important valid concern:
-
sleep infinity
is a GNU coreutils extension not contemplated in POSIX. GNU's implementation also supports a "fancy" syntax for time durations, likesleep 1h 5.2s
while POSIX only allows a positive integer (e.g.sleep 0.5
is not allowed). - Some compatible implementations: GNU coreutils, FreeBSD (at least from version 8.2?), Busybox (requires to be compiled with options
FANCY_SLEEP
andFLOAT_DURATION
). - The
strtod
behaviour is C and POSIX compatible (i.e.strtod("infinity", 0)
is always valid in C99-conformant implementations, see §7.20.1.3).
Solution 5
sleep infinity
looks most elegant, but sometimes it doesn't work for some reason. In that case, you can try other blocking commands such as cat
, read
, tail -f /dev/null
, grep a
etc.
Related videos on Youtube
watain
Updated on July 22, 2021Comments
-
watain almost 3 years
I use
startx
to start X which will evaluate my.xinitrc
. In my.xinitrc
I start my window manager using/usr/bin/mywm
. Now, if I kill my WM (in order to f.e. test some other WM), X will terminate too because the.xinitrc
script reached EOF. So I added this at the end of my.xinitrc
:while true; do sleep 10000; done
This way X won't terminate if I kill my WM. Now my question: how can I do an infinite sleep instead of looping sleep? Is there a command which will kinda like freeze the script?
-
jehon about 2 yearsInteresting... "sleep infinity" to keep X awake :-)
-
-
watain almost 14 yearsIf I use
--replace
I always get a warning likeanother window manager is already running
. That doesn't make much sense to me tho. -
Matt Joiner over 12 yearsThis doesn't work if you don't have a hanging pipe from which to read. Please advise.
-
Michał Trybus over 12 years@Matt, maybe make a pipe and
cat
it?mkfifo pipe && cat pipe
-
not-a-user almost 10 yearsCool. Unfortunately my busybox does not understand.
-
not-a-user almost 10 yearsSignals are asynchronous. So the following can happen: a) shell calls kill b) kill tells kernel that shell shall receive signal STOP c) kill terminates and returns to shell d) shell continues (maybe terminates because script ends) e) kernel finally finds the time to deliver signal STOP to shell
-
michuelnik over 9 years@temple Great insight, didn't think about the asynchronous nature of signals. Thanks!
-
Ivan X about 9 yearsBSD (or at least OS X) doesn't understand
sleep infinity
either, though it was a cool thing to learn about for Linux. However,while true; do sleep 86400; done
ought to be an adequate substitute. -
schmunk about 9 years
tail -f /dev/null
was also a working solution for me on a SaaS platform -
Sudo Bash over 7 years
tail -f /dev/null
also has the advantage of not consuming stdin. I have used it for that reason. -
Tino over 7 yearsThis eats
stdin
if this still happens to be connected to thetty
. If you run it with< /dev/null
it busy-loops. It might be of some use in certain situations, so I do not downvote. -
Mohammed Noureldin over 7 yearsThis is a very bad idea, it will just consume alllot of cpu.
-
Tino about 7 years@Andrew Normally you do not need the
trap
(which modifies the behavior of the shell to signals) nor the background (which allows the shell to intercept signals from the terminal, like Strg+C). Sosleep infinity
is enough (behaves likeexec sleep infinity
if it is the last statement. to see the difference usestrace -ffDI4 bash -c 'YOURCODEHERE'
). The looping sleep is better, becausesleep
can return in certain circumstances. For example you do not want X11 to shut down suddenly on akillall sleep
, just because.xstartup
ends insleep infinity
instead of a sleep loop. -
Patrick over 6 yearsMay be a little obscure, but
s6-pause
is a userland command to runpause()
, optionally ignoring various signals. -
jp48 over 6 yearsRegarding this, I made some research I documented in a separate answer. To summarize:
infinity
is converted in C from "string" to adouble
. Then thatdouble
is truncated to the maximum values allowedtimespec
, which means a very large amount of seconds (architecture-dependant) but, in theory, finite. -
jp48 over 6 yearsWhat @twalberg says, but additionally you can immediately reassign to 3 and unlink it, as shown here: superuser.com/a/633185/762481
-
nh2 over 6 years@Tino
/bin/sleep
is not capped at 24 days as you say. It would be nice if you could update that. On Linux right now, this code is active. It caps individualnanosleep()
syscalls to 24 days, but calls them in a loop. Sosleep infinity
should not exit after 24 days. Thedouble
positive infinity gets converted to astruct timespec
. Looking atrpl_nanosleep
in GDB,infinity
gets converted to{ tv_sec = 9223372036854775807, tv_nsec = 999999999 }
on Ubuntu 16.04. -
Tino over 6 years@nh2 It was already mentioned in the text that sleep probably loops instead of being fully blocking. I edited it now slightly to hopefully make this fact a bit more clear. Please note this "probably", because from
strace
alone I cannot prove the fact that there is really some looping code compiled insleep
, and I do not want to wait 24 days just to test this (or decompile/bin/sleep
). It is always better to program defensively, if there is no hard mathematical proof, that something really is, as it seems to be. Also never trust anything:killall -9 sleep
-
Shadow over 6 yearsThose considering this option should read this answer to learn about the ramifications of this option.
-
tgoodhart about 6 yearsThe pause() option can be done pretty easily with perl: perl -MPOSIX -e 'pause()'
-
Vladimir Panteleev about 4 years
sleep
isn't really capped to 24 days. It breaks the interval into 24-day segments to work around bugs in some operating systems: git.savannah.gnu.org/cgit/gnulib.git/tree/lib/… -
Vladimir Panteleev about 4 yearsIn the next coreutils,
sleep infinity
will now actually sleep forever without looping: lists.gnu.org/archive/html/bug-gnulib/2020-02/msg00081.html -
Vladimir Panteleev about 4 yearsIn the next coreutils,
sleep infinity
will now actually sleep forever without looping: lists.gnu.org/archive/html/bug-gnulib/2020-02/msg00081.html -
ahoffer about 3 yearsI googled "cat abuse". Not sure what I was expecting to find. How about: "No cats were harmed in the execution of this script"
-
Tino about 3 years@VladimirPanteleev nice!
sleep inf
then will callpause()
which gives us all we want. Afterwards my answer can be retired ;) -
Glenn about 3 yearsFWIW, macOS Big Sur now understands "sleep infinity" though Mojave did not. (I skipped Catalina.)
-
Miao1007 about 3 yearsIt will lead to busy waiting(100% CPU) on MacOS.
-
qoomon about 3 years@Miao1007 it only happens with zsh with sh this does not happen. I don't have any clue why this happens in zsh.
-
qoomon about 3 years@Miao1007 I got it, its because
wait
in zsh will resume the given process. -
qoomon about 3 years@Miao1007 I fixed my command by removing
$!
formwait
command. Now its working inzsh
as well. -
kojiro almost 3 years
/bin/sleep infinity
does not work on the Big Sur I'm using. However,gsleep infinity
does. -
sobi3ch over 2 yearsIf your OS doesn't support
sleep infinity
then I suggest runningsleep 365d
assuming your box is restarted at least once a year. -
TJ Zimmerman about 2 yearsThis answer reminds me why I love Stack Overflow lol
-
Vladimir Panteleev about 2 years@jp48
sleep infinity
will now actually sleep forever with the latest GNU coreutils.