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

while true; do sleep 10000; done

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


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


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


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

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

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

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


无限睡眠看起来很优雅,但有时因为某些原因它并不奏效。在这种情况下,您可以尝试其他阻塞命令,如cat, read, tail -f /dev/null, grep a等。


while :; do read; done

没有等待孩子睡觉的过程。


尾部不堵塞

一如既往:任何事情都有一个简短、容易理解、容易理解但完全错误的答案。这里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版本低,但可以工作。

我给你的建议是:

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


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 &在后台创建一个虚拟进程 杀-停止$!停止后台进程 等待后台进程,这将永远阻塞,因为后台进程之前已经停止

笔记

只能从脚本文件中工作。


让我来解释一下为什么无限睡眠是有效的,尽管它没有被记录下来。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;
}