我使用startx来启动X,这将计算我的.xinitrc。在我的.xinitrc中,我使用/usr/bin/mywm.启动我的窗口管理器现在,如果我杀死我的WM(为了f.e.测试其他一些WM), X也将终止,因为.xinitrc脚本到达了EOF。 所以我在.xinitrc的末尾添加了这个:

while true; do sleep 10000; done

这样,如果我终止WM, X就不会终止。现在我的问题是:我如何做一个无限睡眠而不是循环睡眠?是否有类似于冻结脚本的命令?


当前回答

TL;DR:自从GNU coreutils版本9以来,sleep infinity在Linux系统上做了正确的事情。在以前(以及在其他系统中),实现实际上是在允许的最大时间内休眠,这是有限的。


想知道为什么它没有被记录在任何地方,我费心阅读了GNU coreutils的源代码,我发现它大致执行如下:

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 the seconds variable. Invoke xnanosleep(seconds) (found in gnulib), this in turn invokes dtotimespec(seconds) (also in gnulib) to convert from double to struct 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 to TYPE_MAXIMUM(time_t). 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.

这是Linux内核中的TIME_T_MAX,它被定义为(time.h):

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

注意,time_t是__kernel_time_t, time_t是long;使用LP64数据模型,因此sizeof(long)为8(64位)。

结果是:TIME_T_MAX = 9223372036854775807。

也就是说:睡眠无限导致实际睡眠时间为9223372036854775807秒(10^11年)。对于32位linux系统(sizeof(long)是4(32位)):2147483647秒(68年;参见2038年问题)。


编辑:显然,被调用的纳秒函数不是直接的系统调用,而是一个依赖于操作系统的包装器(也在gnulib中定义)。

因此,有一个额外的步骤:对于HAVE_BUG_BIG_NANOSLEEP为真的一些系统,睡眠被截断为24天,然后在循环中调用。这是一些人(或所有人?)Linux发行版。请注意,如果配置时测试成功,则可能不使用此包装器(源)。

具体来说,这将是24 * 24 * 60 * 60 = 2073600秒(加上999999999纳秒);但是为了尊重指定的总睡眠时间,这是在循环中调用的。因此,前面的结论是有效的。


总之,由此产生的睡眠时间不是无限的,但足以满足所有实际目的,即使由此产生的实际时间延迟是不可移植的;这取决于操作系统和架构。

为了回答最初的问题,这显然已经足够好了,但如果出于某种原因(一个资源非常有限的系统),您确实希望避免无用的额外倒计时计时器,我想最正确的替代方法是使用其他答案中描述的cat方法。

编辑:最近的GNU coreutils版本将尝试使用pause系统调用(如果可用)而不是循环。当目标是Linux(可能还有BSD)中的这些新版本时,前面的参数不再有效。


可移植性

这是一个重要而有效的担忧:

sleep infinity is a GNU coreutils extension not contemplated in POSIX. GNU's implementation also supports a "fancy" syntax for time durations, like sleep 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 and FLOAT_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).


其他回答

“无限睡眠”确实做到了它所建议的,而且没有虐待猫。

我最近需要这样做。我提出了下面的函数,它将允许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 "$1"} -u $_snore_fd || :
}

注意:我之前发布了一个版本,每次都会打开和关闭文件描述符,但我发现在一些系统上,每秒执行数百次这样的操作最终会锁定。因此,新的解决方案在函数调用之间保持文件描述符。反正巴斯一出去就会收拾干净的。

它可以像/bin/sleep一样被调用,它将在请求的时间内休眠。调用时不带参数,它将永远挂起。

snore 0.1  # sleeps for 0.1 seconds
snore 10   # sleeps for 10 seconds
snore      # sleeps forever

在我的博客上有一篇写得太多细节的文章

这种方法不会消耗任何资源来保持进程的活动。

while :; do :; done & kill -STOP $! && wait

分解

而:;做的事:;done &在后台创建一个虚拟进程 杀-停止$!停止后台进程 等待后台进程,这将永远阻塞,因为后台进程之前已经停止

笔记

只能从脚本文件中工作。

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

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