我使用startx来启动X,这将计算我的.xinitrc。在我的.xinitrc中,我使用/usr/bin/mywm.启动我的窗口管理器现在,如果我杀死我的WM(为了f.e.测试其他一些WM), X也将终止,因为.xinitrc脚本到达了EOF。 所以我在.xinitrc的末尾添加了这个:
while true; do sleep 10000; done
这样,如果我终止WM, X就不会终止。现在我的问题是:我如何做一个无限睡眠而不是循环睡眠?是否有类似于冻结脚本的命令?
我使用startx来启动X,这将计算我的.xinitrc。在我的.xinitrc中,我使用/usr/bin/mywm.启动我的窗口管理器现在,如果我杀死我的WM(为了f.e.测试其他一些WM), X也将终止,因为.xinitrc脚本到达了EOF。 所以我在.xinitrc的末尾添加了这个:
while true; do sleep 10000; done
这样,如果我终止WM, X就不会终止。现在我的问题是:我如何做一个无限睡眠而不是循环睡眠?是否有类似于冻结脚本的命令?
当前回答
与其杀死窗口管理器,不如尝试使用——replace或-replace(如果可用的话)运行新的窗口管理器。
其他回答
也许这看起来很丑,但为什么不直接运行cat,让它永远等待输入呢?
无限睡眠看起来很优雅,但有时因为某些原因它并不奏效。在这种情况下,您可以尝试其他阻塞命令,如cat, read, tail -f /dev/null, grep a等。
我最近需要这样做。我提出了下面的函数,它将允许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
在我的博客上有一篇写得太多细节的文章
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).
让我来解释一下为什么无限睡眠是有效的,尽管它没有被记录下来。Jp48的答案也很有用。
最重要的是:通过指定inf或infinity(两者都是不区分大小写的),您可以在实现允许的最长时间内休眠(即HUGE_VAL和TYPE_MAXIMUM(time_t)的较小值)。
现在让我们深入研究细节。sleep命令的源代码可以从coreutils/src/sleep.c中读取。本质上,这个函数是这样做的:
double s; //seconds
xstrtod (argv[i], &p, &s, cl_strtod); //`p` is not essential (just used for error check).
xnanosleep (s);
xstrtod (argv[i], &p, &s, cl_strtod)
xstrtod()
根据gnulib/lib/ xstrtod.c.,调用xstrtod()将字符串argv[i]转换为浮点值,并使用转换函数cl_strtod()将其存储为*s。
cl_strtod()
从coreutils/lib/cl- strtod.c.可以看到,cl_strtod()使用strtod()将字符串转换为浮点值。
strtod()
根据man3 strtod, strtod()将字符串转换为double类型的值。手册上说
字符串(初始部分)的预期形式是…或者(iii)无穷大,或者……
无穷被定义为
无穷大可以是“INF”,也可以是“infinity”,不考虑大小写。
尽管文件告诉我们
如果正确的值会导致溢出,则返回+或- HUGE_VAL (HUGE_VALF, HUGE_VALL)
,不清楚如何处理无穷大。让我们看看源代码gnulib/lib/strtod.c.。我们想读的是
else if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'f')
{
s += 3;
if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'i'
&& c_tolower (s[3]) == 't'
&& c_tolower (s[4]) == 'y')
s += 5;
num = HUGE_VAL;
errno = saved_errno;
}
因此,INF和INFINITY(都不区分大小写)被视为HUGE_VAL。
HUGE_VAL家庭
我们用N1570作为C标准。HUGE_VAL, HUGE_VALF和HUGE_VALL宏在§7.12-3中定义
宏 HUGE_VAL 展开为正双常量表达式,不一定能用浮点数表示。的宏 HUGE_VALF HUGE_VALL 分别是HUGE_VAL的float和long双类似物。 在支持无穷大的实现中,HUGE_VAL、HUGE_VALF和HUGE_VALL可以是正无穷大。
在§7.12.1-5中
如果浮动结果溢出且默认舍入生效,则该函数根据返回类型返回宏HUGE_VAL、HUGE_VALF或HUGE_VALL的值
理解xnanosleep
现在我们理解了xstrtod()的所有本质。从上面的解释可以清楚地看出,我们第一次看到的xnanosleep(s)实际上指的是xnanosleep(HUGE_VALL)。
xnanosleep()
根据源代码gnulib/lib/xnanosleep.c, xnanosleep(s)基本上是这样做的:
struct timespec ts_sleep = dtotimespec (s);
nanosleep (&ts_sleep, NULL);
dtotimespec()
该函数将double类型的实参转换为struct timespec类型的对象。由于它非常简单,让我引用源代码gnulib/lib/ dtotimspec .c。所有的评论都是我自己添加的。
struct timespec
dtotimespec (double sec)
{
if (! (TYPE_MINIMUM (time_t) < sec)) //underflow case
return make_timespec (TYPE_MINIMUM (time_t), 0);
else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t))) //overflow case
return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
else //normal case (looks complex but does nothing technical)
{
time_t s = sec;
double frac = TIMESPEC_HZ * (sec - s);
long ns = frac;
ns += ns < frac;
s += ns / TIMESPEC_HZ;
ns %= TIMESPEC_HZ;
if (ns < 0)
{
s--;
ns += TIMESPEC_HZ;
}
return make_timespec (s, ns);
}
}
由于time_t被定义为整型(参见§7.27.1-3),我们自然假设time_t类型的最大值小于HUGE_VAL (double类型),这意味着我们进入溢出情况。(实际上这个假设是不需要的,因为在所有情况下,程序本质上是相同的。)
make_timespec ()
我们必须爬上的最后一堵墙是make_timespec()。非常幸运的是,它非常简单,引用源代码gnulib/lib/ timspech就足够了。
_GL_TIMESPEC_INLINE struct timespec
make_timespec (time_t s, long int ns)
{
struct timespec r;
r.tv_sec = s;
r.tv_nsec = ns;
return r;
}