代码之家  ›  专栏  ›  技术社区  ›  watain

bash:无限睡眠(无限阻塞)

  •  114
  • watain  · 技术社区  · 16 年前

    我用 startx 从x开始,它将评估 .xinitrc . 在我的 新西兰 我用启动窗口管理器 /usr/bin/mywm . 现在,如果我杀死我的wm(为了测试其他wm),x也会终止,因为 新西兰 脚本已到达EOF。 所以我在最后添加了这个 新西兰 :

    while true; do sleep 10000; done
    

    如果我杀了我的wm,x就不会终止。现在我的问题是:我怎样才能 无限睡眠 而不是循环睡眠?有没有一个命令可以冻结脚本?

    最好的问候

    9 回复  |  直到 7 年前
        1
  •  237
  •   Donarsson    12 年前

    sleep infinity 完全按照它的建议行事,而且不会虐待猫。

        2
  •  63
  •   Michał Trybus    16 年前

    也许这看起来很难看,但为什么不快跑呢? cat 让它永远等待输入?

        3
  •  47
  •   Tino    8 年前

    tail 不阻塞

    一如既往:对于每一件事,都有一个简短、易懂、易懂、完全错误的答案。在这里 tail -f /dev/null 属于此类别;)

    如果你用 strace tail -f /dev/null 您会注意到,这个解决方案远没有阻塞!可能比 sleep 解决方案,因为它使用(在Linux下)宝贵的资源,如 inotify 系统。以及其他写入 /dev/null 制作 循环。(在我的Ubuntu64 16.10上,这会在一个已经很忙的系统上每秒增加10次系统调用。)

    问题是关于阻塞命令

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

    阅读:我不知道任何方法可以直接用shell来存档这个。

    一切(甚至 sleep infinity )可以被某个信号中断。所以,如果你真的想确定它不会异常地返回,它必须以一个循环运行,就像你已经为你做的那样。 睡觉 . 请注意,(在Linux上) /bin/sleep 显然,上限是24天(看看 strace sleep infinity ,因此,您可以做的最好的事情可能是:

    while :; do sleep 2073600; done
    

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

    …但是你可以带着一个不知名的 fifo

    只要没有信号发送到进程,就可以创建真正阻塞的对象。以下用途 bash 4 2 pID和1 先进先出 :

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

    你可以检查这是否真的阻止了 strace 如果你喜欢:

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

    这是怎么建造的

    read 如果没有输入数据,则阻止(请参阅其他答案)。然而, tty (又名。 stdin )通常不是一个好的源,因为它在用户注销时关闭。也可能会从 TTY . 不太好。

    使 阅读 布洛克,我们得等一等 先进先出 它永远不会归还任何东西。在 猛击4 有一个命令可以为我们提供 先进先出 : coproc . 如果我们也在等待封锁 阅读 (这是我们的 辅酶 )我们完成了。遗憾的是,这需要保持两个pids和一个 先进先出 .

    变量名为 先进先出

    如果您不想使用 先进先出 ,您可以这样做:

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

    在读取时不使用循环有点草率,但您可以重用它 先进先出 只要你喜欢,就做 阅读 S端接使用 touch "$HOME/.pause.fifo" (如果有多个读取等待,则所有读取都会立即终止)。

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

    对于无限块,有一个Linux内核调用,称为 暂停() 这就是我们想要的:永远等待(直到信号到达)。但是,目前还没有用户空间程序。

    C

    创建这样的程序很容易。下面是创建一个非常小的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
    

    python

    如果你不想自己编译一些东西,但是 蟒蛇 安装后,可以在Linux下使用:

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

    (注:使用 exec python -c ... 要替换当前shell,这将释放一个PID。该解决方案还可以通过一些IO重定向进行改进,释放未使用的FDS。这由你决定。)

    这是如何工作的(我认为): ctypes.CDLL(None) 加载标准C库并运行 暂停() 在它的一些附加循环中运行。比C版本效率低,但有效。

    我的建议是:

    保持循环睡眠。它很容易理解,非常便携,而且大部分时间都被阻塞。

        4
  •  15
  •   jp48    7 年前

    DR: sleep infinity 实际上,睡眠是允许的最长时间,这是有限的。

    我想知道为什么这件事没有记录在案,所以我费心去读了 sources from GNU coreutils 我发现它大致执行如下操作:

    1. 使用 strtod 从第一个参数的C stdlib将“无穷大”转换为双精度。因此,假设IEEE754双精度64位 正无穷大 值存储在 seconds 变量。
    2. 援引 xnanosleep(seconds) ( found in gnulib ,这反过来调用 dtotimespec(seconds) ( also in gnulib )转换自 double struct timespec .
    3. TimeSimult结构 只是一对数字:整数部分(以秒为单位)和小数部分(以纳秒为单位)。 不完全转换 正无穷大 to integer将导致未定义的行为(参见C标准中的_6.3.1.4),因此它将截断为 TYPE_MAXIMUM (time_t) .
    4. 的实际值 类型\最大值(时间\u t) 未在标准中设置(偶数 sizeof(time_t) 不是);因此,为了举例,让我们从最近的Linux内核中选择x86-64。

    这是 TIME_T_MAX 在Linux内核中,( time.h ):

    (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
    

    注意 time_t __kernel_time_t Timet long ;使用了lp64数据模型,因此 sizeof(long) 是8(64位)。

    结果是: TIME_T_MAX = 9223372036854775807 .

    即: sleep infinite 结果实际睡眠时间为9223372036854775807秒(10^11年)。以及32位Linux系统( 西泽夫(长) 是4(32位):2147483647秒(68年;另请参见 year 2038 problem )


    编辑 :显然 nanoseconds 被调用的函数不是直接的syscall,而是一个与操作系统相关的包装器(也是 defined in gnulib )

    因此,还有一个额外的步骤:对于某些系统 HAVE_BUG_BIG_NANOSLEEP true 睡眠被截断为24天,然后在循环中调用。有些人(或全部)就是这样。Linux发行版请注意,如果 配置 -时间测试成功( source )

    尤其是,那将是 24 * 24 * 60 * 60 = 2073600 seconds (加上999999999纳秒);但这是在循环中调用的,以考虑指定的总睡眠时间。因此,先前的结论仍然有效。


    总之,由此产生的睡眠时间 不是无限的,但对于所有实际用途来说都足够高 ,即使所产生的实际时间间隔不可移植;这取决于操作系统和体系结构。

    为了回答最初的问题,这显然足够好,但如果出于某种原因(a 非常 资源受限的系统)你真的想避免一个无用的额外倒计时计时器,我想最正确的选择是使用 cat 其他答案中描述的方法。

        5
  •  8
  •   Hui Zheng    11 年前

    sleep infinity 看起来很优雅,但有时因为某种原因不起作用。在这种情况下,您可以尝试其他阻塞命令,例如 cat , read , tail -f /dev/null , grep a 等。

        6
  •  5
  •   michuelnik    9 年前

    发送一个 SIGSTOP 对自己?

    这应该暂停进程,直到接收到SIGCont。这是你的情况:永远不会。

    kill -STOP "$$";
    # grace time for signal delivery
    sleep 60;
    
        7
  •  2
  •   bolt    8 年前

    我最近有必要这么做。我提出了以下功能,允许bash在不调用任何外部程序的情况下永远休眠:

    snore()
    {
        [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:)
        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
    

    There's a writeup with excessive details on my blog here

        8
  •  0
  •   Dennis Williamson    16 年前

    与其杀死窗口管理器,不如试着用 --replace -replace 如果有的话。

        9
  •  -2
  •   shuaiming    10 年前
    while :; do read; done
    

    无需等待儿童睡眠过程。

    推荐文章