wat*_*ain 135 linux bash sleep infinite
我startx用来启动X来评估我的.xinitrc.在我的.xinitrc开始我的窗口管理器使用/usr/bin/mywm.现在,如果我杀了我的WM(为了测试其他一些WM),X也将因为.xinitrc脚本达到EOF而终止.所以我在最后添加了这个.xinitrc:
while true; do sleep 10000; done
Run Code Online (Sandbox Code Playgroud)
这样,如果我杀了我的WM,X就不会终止.现在我的问题是:如何进行无限次睡眠而不是循环睡眠?有没有一个命令有点像冻结脚本?
最好的祝福
Don*_*son 282
sleep infinity 确切地说它的建议和工作没有虐待猫.
Mic*_*bus 69
也许这看起来很丑陋,但为什么不跑cat,让它等待输入永远?
Tin*_*ino 61
tail 不阻止一如既往:对于一切都有一个简短,易于理解,易于遵循和完全错误的答案.这里tail -f /dev/null属于这一类;)
如果你看一下,strace tail -f /dev/null你会注意到,这个解决方案远非阻塞!它可能比问题中的sleep解决方案更糟糕,因为它使用(在Linux下)像inotify系统这样的宝贵资源.还有其他写入/dev/nullmake tail循环的进程.(在我的Ubuntu64 16.10上,这在已经繁忙的系统上每秒增加了10个系统调用.)
阅读:我不知道有任何方法可以直接将shell归档.
sleep infinity一些信号可以打断一切(偶数).因此,如果你想确定它没有异常返回,它必须在循环中运行,就像你已经为你做的那样sleep.请注意,(在Linux上)/bin/sleep显然是限制在24天(看看strace sleep infinity),因此你可以做的最好的可能是:
while :; do sleep 2073600; done
Run Code Online (Sandbox Code Playgroud)
(请注意,我认为sleep内部循环的值高于24天,但这意味着:它没有阻塞,循环非常缓慢.那么为什么不将此循环移到外面?)
fifo只要没有信号发送到进程,您就可以创建真正阻塞的东西.以下使用bash 4,2个PID和1 fifo:
bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'
Run Code Online (Sandbox Code Playgroud)
strace如果你愿意,你可以检查这是否真的阻止:
strace -ff bash -c '..see above..'
Run Code Online (Sandbox Code Playgroud)
read如果没有输入数据则阻塞(参见其他答案).但是,tty(aka.stdin)通常不是一个好的来源,因为它在用户注销时关闭.它也可能从中窃取一些输入tty.不太好.
为了read阻止,我们需要等待一些fifo永远不会返回的东西.在bash 4那里是可以准确地为我们提供了这样的一个命令fifo:coproc.如果我们也等待阻止read(这是我们的coproc),我们就完成了.遗憾的是,这需要保持打开两个PID和一个fifo.
fifo如果您不打扰使用命名fifo,可以按如下方式执行此操作:
mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"
Run Code Online (Sandbox Code Playgroud)
在读取时不使用循环有点草率,但您可以根据需要重复使用它fifo并read使用s终止touch "$HOME/.pause.fifo"(如果有多个读取等待,则所有都立即终止).
pause()系统调用对于无限阻塞,有一个称为Linux内核的调用,pause()它可以完成我们想要的任务:永远等待(直到信号到达).但是,目前还没有用户空间程序.
创建这样的程序很容易.下面是一个片段,以创建一个名为一个非常小的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
Run Code Online (Sandbox Code Playgroud)
python如果您不想自己编译,但已python安装,可以在Linux下使用:
python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'
Run Code Online (Sandbox Code Playgroud)
(注意:exec python -c ...用于替换当前shell,这将释放一个PID.解决方案也可以通过一些IO重定向进行改进,释放未使用的FD.这取决于您.)
这是如何工作的(我认为):ctypes.CDLL(None)加载标准C库并pause()在一些额外的循环中运行其中的函数.效率低于C版本,但有效.
保持循环睡眠.它易于理解,非常便携,并且在大多数情况下都会阻止.
jp4*_*p48 24
TL; DR:sleep infinity实际上是睡眠允许的最大时间,这是有限的.
想知道为什么没有在任何地方记录这一点,我打扰从GNU coreutils读取源代码,我发现它大致执行如下:
strtod在第一个参数上使用C stdlib将'无穷大'转换为双精度.因此,假设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.这是TIME_T_MAX在Linux内核中,其定义为(time.h)为:
(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
Run Code Online (Sandbox Code Playgroud)
请注意,time_t是__kernel_time_t和time_t是long; 使用LP64数据模型,因此sizeof(long)是8(64位).
结果如下:TIME_T_MAX = 9223372036854775807.
即:sleep infinite导致实际睡眠时间为9223372036854775807秒(10 ^ 11年).对于32位Linux系统(sizeof(long)4(32位)):2147483647秒(68年;另见2038年问题).
编辑:显然,nanoseconds调用的函数不是直接的系统调用,而是依赖于操作系统的包装器(也在gnulib中定义).
这里有一个额外的步骤,其结果是:对于一些系统中HAVE_BUG_BIG_NANOSLEEP是true睡眠被截断至24天,然后在循环中调用.某些(或所有?)Linux发行版就是这种情况.请注意,如果configure -time测试成功(源),则可能不使用此包装器.
特别是,那将是24 * 24 * 60 * 60 = 2073600 seconds(加999999999纳秒); 但是这是在循环中调用的,以便遵守指定的总睡眠时间.因此,先前的结论仍然有效.
总之,即使由此产生的实际时间流逝不可移动,所产生的睡眠时间也不是无限的,但对于所有实际目的而言都足够高 ; 这取决于操作系统和架构.
回答原来的问题,这显然已经足够好但是如果由于某种原因(一个资源非常有限的系统)你真的想避免一个无用的额外倒数计时器,我想最正确的选择是使用cat其他答案中描述的方法.
让我解释一下为什么sleep infinity有效,尽管它没有记录。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);
Run Code Online (Sandbox Code Playgroud)
xstrtod (argv[i], &p, &s, cl_strtod)xstrtod()
根据gnulib/lib/xstrtod.c,调用xstrtod()将字符串转换argv[i]为浮点值并将其存储到*s,使用转换函数cl_strtod()。
cl_strtod()
从coreutils/lib/cl-strtod.c可以看出,cl_strtod()将字符串转换为浮点值,使用strtod().
strtod()
根据man 3 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;
}
Run Code Online (Sandbox Code Playgroud)
因此,INF和INFINITY(均不区分大小写)被视为HUGE_VAL。
HUGE_VAL 家庭
让我们使用N1570作为 C 标准。HUGE_VAL,HUGE_VALF和HUGE_VALL宏定义在§7.12-3
宏
HUGE_VAL
扩展为正双常量表达式,不一定可以表示为浮点数。宏
HUGE_VALF
HUGE_VALL
分别是 float 和 long double 的类似物HUGE_VAL。
HUGE_VAL,HUGE_VALF, 和HUGE_VALL在支持无穷大的实现中可以是正无穷大。
并在 §7.12.1-5
如果浮动结果溢出和默认的舍入有效时,则该函数返回的宏的值
HUGE_VAL,HUGE_VALF或HUGE_VALL根据返回类型
xnanosleep (s)现在我们了解了xstrtod(). 从上面的解释中,很明显xnanosleep(s)我们看到的第一个实际上是xnanosleep(HUGE_VALL)。
xnanosleep()
根据源代码gnulib/lib/xnanosleep.c,xnanosleep(s)基本上是这样做的:
struct timespec ts_sleep = dtotimespec (s);
nanosleep (&ts_sleep, NULL);
Run Code Online (Sandbox Code Playgroud)
dtotimespec()
此函数将类型的参数转换为类型double的对象struct timespec。既然很简单,我就引用一下源代码gnulib/lib/dtotimespec.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);
}
}
Run Code Online (Sandbox Code Playgroud)
由于time_t被定义为整数类型(参见第 7.27.1-3 节),我们很自然地假设 type 的最大值time_t小于HUGE_VAL(of type double),这意味着我们进入溢出情况。(实际上不需要这个假设,因为在所有情况下,过程基本上是相同的。)
make_timespec()
我们必须爬上的最后一堵墙是make_timespec()。非常幸运,它是如此简单,引用源代码gnulib/lib/timespec.h就足够了。
_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;
}
Run Code Online (Sandbox Code Playgroud)
sleep infinity看起来最优雅,但有时由于某种原因它不起作用.在这种情况下,你可以尝试其他的拦截命令,如cat,read,tail -f /dev/null,grep a等.
如何向自己发送SIGSTOP?
这应暂停该过程,直到收到SIGCONT.在你的情况下:永远不会.
kill -STOP "$$";
# grace time for signal delivery
sleep 60;
Run Code Online (Sandbox Code Playgroud)