我使用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就不会终止。现在我的问题是:我如何做一个无限睡眠而不是循环睡眠?是否有类似于冻结脚本的命令?
当前回答
让我来解释一下为什么无限睡眠是有效的,尽管它没有被记录下来。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;
}
其他回答
尾部不堵塞
一如既往:任何事情都有一个简短、容易理解、容易理解但完全错误的答案。这里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版本低,但可以工作。
我给你的建议是:
停留在循环睡眠。它很容易理解,非常便携,而且大多数时候都是阻塞的。
“无限睡眠”确实做到了它所建议的,而且没有虐待猫。
与其杀死窗口管理器,不如尝试使用——replace或-replace(如果可用的话)运行新的窗口管理器。
也许这看起来很丑,但为什么不直接运行cat,让它永远等待输入呢?
这种方法不会消耗任何资源来保持进程的活动。
while :; do :; done & kill -STOP $! && wait
分解
而:;做的事:;done &在后台创建一个虚拟进程 杀-停止$!停止后台进程 等待后台进程,这将永远阻塞,因为后台进程之前已经停止
笔记
只能从脚本文件中工作。