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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 20:04:40  来源:igfitidea点击:

Bash: infinite sleep (infinite blocking)

linuxbashsleepinfinite

提问by watain

I use startxto start X which will evaluate my .xinitrc. In my .xinitrcI 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 .xinitrcscript 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 infinitydoes exactly what it suggests and works without cat abuse.

sleep infinity完全按照它的建议行事,并且不会虐待猫。

回答by Micha? Trybus

Maybe this seems ugly, but why not just run catand let it wait for input forever?

也许这看起来很难看,但为什么不直接运行cat并让它永远等待输入呢?

回答by Paused until further notice.

Instead of killing the window manager, try running the new one with --replaceor -replaceif available.

与其关闭窗口管理器,不如尝试使用--replace或运行新的窗口管理器(-replace如果可用)。

回答by michuelnik

What about sending a SIGSTOPto itself?

向自己发送SIGSTOP怎么样?

This should pause the process until SIGCONT is received. Which is in your case: never.

这应该暂停进程,直到收到 SIGCONT。这就是你的情况:从不。

kill -STOP "$$";
# grace time for signal delivery
sleep 60;

回答by Hui Zheng

sleep infinitylooks 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 aetc.

sleep infinity看起来最优雅,但有时​​由于某种原因它不起作用。在这种情况下,你可以尝试其他的拦截命令,如catreadtail -f /dev/nullgrep a等。

回答by shuaiming

while :; do read; done

no waiting for child sleeping process.

没有等待孩子的睡眠过程。

回答by Tino

taildoes 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/nullfalls into this category ;)

一如既往:对于任何事情,都有一个简短、易于理解、易于遵循且完全错误的答案。这里tail -f /dev/null属于这一类;)

If you look at it with strace tail -f /dev/nullyou will notice, that this solution is far from blocking! It's probably even worse than the sleepsolution in the question, as it uses (under Linux) precious resources like the inotifysystem. Also other processes which write to /dev/nullmake tailloop. (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/sleepapparently 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 sleeploops 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 straceif you like:

strace如果您愿意,您可以检查这是否真的阻塞:

strace -ff bash -c '..see above..'

How this was constructed

这是如何构建的

readblocks 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 readblock, we need to wait for something like a fifowhich will never return anything. In bash 4there 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那里是可以准确地为我们提供了这样的一个命令fifocoproc。如果我们也等待阻塞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 fifoas often as you like and make the reads terminat using touch "$HOME/.pause.fifo"(if there are more than a single read waiting, all are terminated at once).

在读取上不使用循环有点草率,但是您可以根据需要多次重复使用它fiforead使用 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 pausewhich pauses indefinitely (needs diet, gccetc.):

创建这样的程序很容易。下面是一个片段,以创建一个名为一个非常小的Linux程序pause,其无限期暂停(需求dietgcc等):

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 pythoninstalled, 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 infinityactually 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源代码,我发现它大致执行如下:

  1. Use strtodfrom 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 the secondsvariable.
  2. Invoke xnanosleep(seconds)(found in gnulib), this in turn invokes dtotimespec(seconds)(also in gnulib) to convert from doubleto struct timespec.
  3. struct timespecis 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 to TYPE_MAXIMUM (time_t).
  4. The actual value of TYPE_MAXIMUM (time_t)is not set in the standard (even sizeof(time_t)isn't); so, for the sake of example let's pick x86-64 from a recent Linux kernel.
  1. strtod在第一个参数上使用from C stdlib 将 'infinity' 转换为双精度。因此,假设 IEEE 754 双精度,64 位正无穷大值存储在seconds变量中。
  2. 调用xnanosleep(seconds)在 gnulib 中找到),这反过来调用dtotimespec(seconds)也在 gnulib 中)转换doublestruct timespec
  3. struct timespec只是一对数字:整数部分(以秒为单位)和小数部分(以纳秒为单位)。简单地将正无穷大转换为整数会导致未定义的行为(请参阅 C 标准中的第 6.3.1.4 节),因此将其截断为TYPE_MAXIMUM (time_t).
  4. TYPE_MAXIMUM (time_t)标准中没有设置的实际值(甚至sizeof(time_t)没有);因此,为了举例,让我们从最近的 Linux 内核中选择 x86-64。

This is TIME_T_MAXin 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_tis __kernel_time_tand time_tis long; the LP64 data model is used, so sizeof(long)is 8 (64 bits).

请注意time_t__kernel_time_ttime_tlong; 使用 LP64 数据模型,因此使用sizeof(long)8(64 位)。

Which results in: TIME_T_MAX = 9223372036854775807.

结果是:TIME_T_MAX = 9223372036854775807.

That is: sleep infiniteresults 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 nanosecondsfunction 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_NANOSLEEPis truethe 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_NANOSLEEPtrue睡眠被截断至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 catmethod 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

There's a writeup with excessive details on my blog here

在我的博客上有一篇文章,其中包含过多的细节

回答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 background
  • kill -STOP $!Stops the background process
  • wait $!Wait for the background process, this will be blocking forever, cause background process was stopped before
  • while :; do sleep 1; done &在后台创建一个虚拟进程
  • kill -STOP $!停止后台进程
  • wait $!等待后台进程,这将永远阻塞,导致后台进程之前停止