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

while true; do sleep 10000; done

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


当前回答

尾部不堵塞

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

如果你用strace tail -f /dev/null来观察它,你会发现这个解决方案远远没有阻塞!它可能比问题中的睡眠解决方案更糟糕,因为它使用(在Linux下)像inotify系统这样的宝贵资源。其他写入/dev/null的进程也会形成尾循环。(在我的Ubuntu64 16.10上,这在一个已经很忙的系统上增加了每秒10个系统调用。)

这个问题是关于阻塞命令的

不幸的是,没有这样的事情。

阅读:我不知道任何方法来归档这与壳直接。

一切(甚至无限睡眠)都可能被某种信号打断。所以如果你真的想确保它不会异常返回,它必须在循环中运行,就像你睡觉时做的那样。请注意,(在Linux上)/bin/sleep显然被限制在24天(看看strace sleep infinity),因此你能做的最好的可能是:

while :; do sleep 2073600; done

(注意,我认为睡眠循环的内在值高于24天,但这意味着:它不是阻塞,它是非常缓慢的循环。那么为什么不把这个循环移到外面呢?)

. .但是你可以用一个未命名的fifo来接近它

你可以创建一些真正阻塞的东西,只要没有信号发送到进程。下面使用bash 4,2 pid和1 fifo:

bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'

如果你喜欢,你可以用strace检查它是否真的阻塞:

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

这是怎么建造的

如果没有输入数据,则读取块(参见其他答案)。然而,tty (aka。Stdin)通常不是一个好的源,因为当用户注销时它就关闭了。它还可能从tty中窃取一些输入。不好。

为了创建read块,我们需要等待像fifo这样永远不会返回任何东西的东西。在bash 4中,有一个命令可以为我们提供这样的fifo: coproc。如果我们还等待阻塞读取(这是我们的coproc),我们就完成了。可悲的是,这需要保持开放的两个pid和一个先进先出。

具有命名fifo的变体

如果你不想使用命名fifo,你可以这样做:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

在读取时不使用循环有点草率,但你可以经常重用这个fifo,并使用touch "$HOME/.pause "使读取终止。Fifo”(如果有多个读等待,所有的都被立即终止)。

或者使用Linux pause()系统调用

对于无限阻塞,有一个名为pause()的Linux内核调用,它做我们想要的事情:永远等待(直到信号到达)。然而,目前还没有用户空间程序。

C

创建这样一个程序很容易。下面是创建一个名为pause的非常小的Linux程序的代码片段,它可以无限期地暂停(需要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,你可以在Linux下使用:

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(注意:使用exec python -c…替换当前的外壳,这释放了一个PID。该解决方案还可以通过一些IO重定向进行改进,释放未使用的fd。这取决于你。)

这是如何工作的(我认为):ctypes.CDLL(None)加载标准C库,并在一些额外的循环中运行pause()函数。效率比C版本低,但可以工作。

我给你的建议是:

停留在循环睡眠。它很容易理解,非常便携,而且大多数时候都是阻塞的。

其他回答

那么发送一个SIGSTOP给它自己呢?

这将暂停进程,直到接收到SIGCONT。在你的情况下,永远不会。

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

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

尾部不堵塞

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

如果你用strace tail -f /dev/null来观察它,你会发现这个解决方案远远没有阻塞!它可能比问题中的睡眠解决方案更糟糕,因为它使用(在Linux下)像inotify系统这样的宝贵资源。其他写入/dev/null的进程也会形成尾循环。(在我的Ubuntu64 16.10上,这在一个已经很忙的系统上增加了每秒10个系统调用。)

这个问题是关于阻塞命令的

不幸的是,没有这样的事情。

阅读:我不知道任何方法来归档这与壳直接。

一切(甚至无限睡眠)都可能被某种信号打断。所以如果你真的想确保它不会异常返回,它必须在循环中运行,就像你睡觉时做的那样。请注意,(在Linux上)/bin/sleep显然被限制在24天(看看strace sleep infinity),因此你能做的最好的可能是:

while :; do sleep 2073600; done

(注意,我认为睡眠循环的内在值高于24天,但这意味着:它不是阻塞,它是非常缓慢的循环。那么为什么不把这个循环移到外面呢?)

. .但是你可以用一个未命名的fifo来接近它

你可以创建一些真正阻塞的东西,只要没有信号发送到进程。下面使用bash 4,2 pid和1 fifo:

bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'

如果你喜欢,你可以用strace检查它是否真的阻塞:

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

这是怎么建造的

如果没有输入数据,则读取块(参见其他答案)。然而,tty (aka。Stdin)通常不是一个好的源,因为当用户注销时它就关闭了。它还可能从tty中窃取一些输入。不好。

为了创建read块,我们需要等待像fifo这样永远不会返回任何东西的东西。在bash 4中,有一个命令可以为我们提供这样的fifo: coproc。如果我们还等待阻塞读取(这是我们的coproc),我们就完成了。可悲的是,这需要保持开放的两个pid和一个先进先出。

具有命名fifo的变体

如果你不想使用命名fifo,你可以这样做:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

在读取时不使用循环有点草率,但你可以经常重用这个fifo,并使用touch "$HOME/.pause "使读取终止。Fifo”(如果有多个读等待,所有的都被立即终止)。

或者使用Linux pause()系统调用

对于无限阻塞,有一个名为pause()的Linux内核调用,它做我们想要的事情:永远等待(直到信号到达)。然而,目前还没有用户空间程序。

C

创建这样一个程序很容易。下面是创建一个名为pause的非常小的Linux程序的代码片段,它可以无限期地暂停(需要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,你可以在Linux下使用:

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(注意:使用exec python -c…替换当前的外壳,这释放了一个PID。该解决方案还可以通过一些IO重定向进行改进,释放未使用的fd。这取决于你。)

这是如何工作的(我认为):ctypes.CDLL(None)加载标准C库,并在一些额外的循环中运行pause()函数。效率比C版本低,但可以工作。

我给你的建议是:

停留在循环睡眠。它很容易理解,非常便携,而且大多数时候都是阻塞的。

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

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).