Linux Bash:无限睡眠(无限阻塞)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2935183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash: infinite sleep (infinite blocking)
提问by watain
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
:
我startx
用来启动 X 它将评估我的.xinitrc
. 在我中,.xinitrc
我使用/usr/bin/mywm
. 现在,如果我杀死我的 WM(为了测试其他 WM),X 也会终止,因为.xinitrc
脚本达到 EOF。所以我在我的末尾添加了这个.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 sleepinstead of looping sleep? Is there a command which will kinda like freeze the script?
这样,如果我杀死我的 WM,X 就不会终止。现在我的问题是:如何进行无限睡眠而不是循环睡眠?是否有类似于冻结脚本的命令?
Best regards
此致
采纳答案by Donarsson
sleep infinity
does exactly what it suggests and works without cat abuse.
sleep infinity
完全按照它的建议行事,并且不会虐待猫。
回答by Micha? Trybus
Maybe this seems ugly, but why not just run cat
and let it wait for input forever?
也许这看起来很难看,但为什么不直接运行cat
并让它永远等待输入呢?
回答by Paused until further notice.
Instead of killing the window manager, try running the new one with --replace
or -replace
if available.
与其关闭窗口管理器,不如尝试使用--replace
或运行新的窗口管理器(-replace
如果可用)。
回答by michuelnik
回答by Hui Zheng
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.
sleep infinity
看起来最优雅,但有时由于某种原因它不起作用。在这种情况下,你可以尝试其他的拦截命令,如cat
,read
,tail -f /dev/null
,grep a
等。
回答by shuaiming
while :; do read; done
no waiting for child sleeping process.
没有等待孩子的睡眠过程。
回答by Tino
tail
does not block
tail
不阻塞
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 ;)
一如既往:对于任何事情,都有一个简短、易于理解、易于遵循且完全错误的答案。这里tail -f /dev/null
属于这一类;)
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.)
如果你和你一起看它,strace tail -f /dev/null
你会注意到,这个解决方案远非阻塞!它可能比问题中的sleep
解决方案更糟糕,因为它使用(在 Linux 下)inotify
系统等宝贵资源。其中写到还有一些其它过程/dev/null
使tail
循环。(在我的 Ubuntu64 16.10 上,这会在已经很忙的系统上每秒增加 10 个系统调用。)
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.
阅读:我不知道有什么方法可以直接用 shell 存档。
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:
一切(甚至sleep infinity
)都可以被某个信号中断。因此,如果您想真正确定它不会异常返回,则它必须在循环中运行,就像您已经为sleep
. 请注意,(在 Linux 上)/bin/sleep
显然是 24 天(看看strace sleep infinity
),因此你能做的最好的可能是:
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?)
(请注意,我认为sleep
内部循环的值高于 24 天,但这意味着:它没有阻塞,循环非常缓慢。那么为什么不将此循环移到外部呢?)
.. but you can come quite near with an unnamed fifo
..但是你可以接近一个未命名的 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 4
,2 个 PID 和 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
如果您愿意,您可以检查这是否真的阻塞:
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.
read
如果没有输入数据,则阻止(请参阅其他一些答案)。然而,tty
(又名。stdin
)通常不是一个好的来源,因为它在用户注销时被关闭。它也可能从tty
. 不太好。
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
.
要创建read
块,我们需要等待诸如 a 之类的东西fifo
,它永远不会返回任何东西。在bash 4
那里是可以准确地为我们提供了这样的一个命令fifo
:coproc
。如果我们也等待阻塞read
(这是我们的coproc
),我们就完成了。遗憾的是,这需要保持打开两个 PID 和一个fifo
.
Variant with a named fifo
具有命名的变体 fifo
If you do not bother using a named fifo
, you can do this as follows:
如果您不打扰使用 named fifo
,您可以按如下方式执行此操作:
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).
在读取上不使用循环有点草率,但是您可以根据需要多次重复使用它fifo
并read
使用 s 终止touch "$HOME/.pause.fifo"
(如果有多个读取等待,所有读取都会立即终止)。
Or use the Linux pause()
syscall
或者使用 Linuxpause()
系统调用
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).
对于无限阻塞,有一个名为 的 Linux 内核调用,pause()
它执行我们想要的操作:永远等待(直到信号到达)。但是(目前)还没有用于此的用户空间程序。
C
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.):
创建这样的程序很容易。下面是一个片段,以创建一个名为一个非常小的Linux程序pause
,其无限期暂停(需求diet
,gcc
等):
printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause
python
python
If you do not want to compile something yourself, but you have python
installed, you can use this under Linux:
如果你不想自己编译一些东西,但是你已经python
安装了,你可以在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.)
(注意:exec python -c ...
用于替换当前的 shell,这会释放一个 PID。该解决方案也可以通过一些 IO 重定向来改进,释放未使用的 FD。这取决于您。)
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.
这是如何工作的(我认为):ctypes.CDLL(None)
加载标准 C 库并pause()
在一些附加循环中运行其中的函数。效率低于 C 版本,但有效。
My recommendation for you:
我给你的建议:
Stay at the looping sleep. It's easy to understand, very portable, and blocks most of the time.
保持循环睡眠。它很容易理解,非常便携,并且大部分时间都是阻塞的。
回答by jp48
TL;DR: sleep infinity
actually sleeps the maximum time allowed, which is finite.
TL;DR:sleep infinity
实际上睡眠允许的最长时间,这是有限的。
Wondering why this is not documented anywhere, I bothered to read the sources from GNU coreutilsand I found it executes roughly what follows:
想知道为什么这没有在任何地方记录,我费心阅读GNU coreutils的源代码,我发现它大致执行如下:
- Use
strtod
from C stdlib on the first argument to convert 'infinity' to the double precision. So, assuming IEEE 754 double precision the 64-bit positive infinityvalue 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 infinityto 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.
strtod
在第一个参数上使用from C stdlib 将 'infinity' 转换为双精度。因此,假设 IEEE 754 双精度,64 位正无穷大值存储在seconds
变量中。- 调用
xnanosleep(seconds)
(在 gnulib 中找到),这反过来调用dtotimespec(seconds)
(也在 gnulib 中)转换double
为struct timespec
。 struct timespec
只是一对数字:整数部分(以秒为单位)和小数部分(以纳秒为单位)。简单地将正无穷大转换为整数会导致未定义的行为(请参阅 C 标准中的第 6.3.1.4 节),因此将其截断为TYPE_MAXIMUM (time_t)
.TYPE_MAXIMUM (time_t)
标准中没有设置的实际值(甚至sizeof(time_t)
没有);因此,为了举例,让我们从最近的 Linux 内核中选择 x86-64。
This is TIME_T_MAX
in the Linux kernel, which is defined (time.h
) as:
这是TIME_T_MAX
在 Linux 内核中,其定义 ( time.h
) 为:
(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).
请注意time_t
是__kernel_time_t
和time_t
是long
; 使用 LP64 数据模型,因此使用sizeof(long)
8(64 位)。
Which results in: TIME_T_MAX = 9223372036854775807
.
结果是: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).
即:sleep infinite
导致实际睡眠时间为 9223372036854775807 秒(10^11 年)。对于 32 位 linux 系统(sizeof(long)
是 4(32 位)):2147483647 秒(68 年;另见2038 年问题)。
Edit: apparently the nanoseconds
function called is not directly the syscall, but an OS-dependent wrapper (also defined in gnulib).
编辑:显然,nanoseconds
调用的函数不是直接的系统调用,而是依赖于操作系统的包装器(也在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).
这里有一个额外的步骤,其结果是:对于一些系统中HAVE_BUG_BIG_NANOSLEEP
是true
睡眠被截断至24天,然后在循环中调用。某些(或全部?)Linux 发行版就是这种情况。请注意,如果配置时间测试成功(源),则可能不使用此包装器。
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.
特别是,那将是24 * 24 * 60 * 60 = 2073600 seconds
(加上 999999999 纳秒);但这是在循环中调用以遵守指定的总睡眠时间。因此,之前的结论仍然有效。
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 veryresource-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.
要回答最初的问题,这显然已经足够好了,但是如果由于某种原因(资源非常有限的系统)您真的想避免使用无用的额外倒数计时器,我想最正确的选择是使用cat
其他答案中描述的方法.
回答by bolt
I recently had a need to do this. I came up with the following function that will allow bash to sleep forever without calling any external program:
我最近需要这样做。我想出了以下函数,它可以让 bash 永远休眠而不调用任何外部程序:
snore()
{
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null ||
{
# workaround for MacOS and similar systems
local fifo
fifo=$(mktemp -u)
mkfifo -m 700 "$fifo"
exec {_snore_fd}<>"$fifo"
rm "$fifo"
}
read ${1:+-t ""} -u $_snore_fd || :
}
NOTE: I previously posted a version of this that would open and close the file descriptor each time, but I found that on some systems doing this hundreds of times a second would eventually lock up. Thus the new solution keeps the file descriptor between calls to the function. Bash will clean it up on exit anyway.
注意:我之前发布了一个每次都会打开和关闭文件描述符的版本,但我发现在某些系统上每秒执行数百次最终会锁定。因此,新解决方案在函数调用之间保留文件描述符。无论如何,Bash 会在退出时清理它。
This can be called just like /bin/sleep, and it will sleep for the requested time. Called without parameters, it will hang forever.
这可以像 /bin/sleep 一样调用,它会在请求的时间内休眠。不带参数调用,它将永远挂起。
snore 0.1 # sleeps for 0.1 seconds
snore 10 # sleeps for 10 seconds
snore # sleeps forever
回答by qoomon
This approach will not consume any resources for keeping process alive.
这种方法不会消耗任何资源来保持进程处于活动状态。
while :; do sleep 1; done & kill -STOP $! && wait $!
while :; do sleep 1; done & kill -STOP $! && wait $!
Breakdown
分解
while :; do sleep 1; done &
Creates a dummy process in backgroundkill -STOP $!
Stops the background processwait $!
Wait for the background process, this will be blocking forever, cause background process was stopped before
while :; do sleep 1; done &
在后台创建一个虚拟进程kill -STOP $!
停止后台进程wait $!
等待后台进程,这将永远阻塞,导致后台进程之前停止