from–https://code-examples.net/zh-CN/q/2cc98f
bash sleep ms (9)
tail
不阻挡
一如既往:对于所有事情,都有一个简短,易于理解,易于遵循且完全错误的答案。 这里tail -f /dev/null
属于这个类别;)
如果你用strace tail -f /dev/null
来看它,你会注意到,这个解决方案远非阻塞! 这可能比问题中的sleep
解决方案还要糟糕,因为它使用(在Linux下)像inotify
系统这样的宝贵资源。 写入/dev/null
其他进程/dev/null
导致tail
循环。 (在我的Ubuntu64 16.10上,这在已经繁忙的系统上每秒增加几十个系统调用。)
问题是阻塞命令
不幸的是,没有这样的事情..
阅读:我不知道任何方式直接存档与外壳。
一切(甚至sleep infinity
)都可能被一些信号中断。 所以如果你想确定它不会异常返回,它必须在循环中运行,就像你已经为你的sleep
做了一样。 请注意,(在Linux上) /bin/sleep
显然是在24天限制的(看看strace sleep infinity
),因此最好的做法可能是:
while :; do sleep 2073600; done
(请注意,我相信sleep
内部循环的值高于24天,但这意味着:它不会阻塞,它非常缓慢地循环,所以为什么不把它移到外面?)
..但你可以非常接近一个无名的fifo
只要没有信号发送到进程,您就可以创建一个真正阻塞的东西。 以下使用bash 4
个PID和1个fifo
:
bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'
如果你喜欢,你可以检查这是否真的阻止了strace
:
strace -ff bash -c '..see above..'
这是如何构建的
如果没有输入数据,则read
块(请参阅其他答案)。 但是, tty
( 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"
读取时不使用循环有点草率,但可以随时重复使用此fifo
,并使用touch "$HOME/.pause.fifo"
使read
终止(如果有多个读取等待,全部都立即终止)。
或者使用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 ...
来替换当前的shell,这可以释放一个PID,并且可以通过一些IO重定向来改进解决方案,释放未使用的FD,这取决于您。
这是如何工作的(我认为): ctypes.CDLL(None)
加载标准的C库,并在一些额外的循环内运行pause()
函数。 效率低于C版本,但有效。
我对你的建议是:
留在循环睡眠。 它很容易理解,非常便携,并且大部分时间都会阻塞。
我使用startx
来启动X来评估我的.xinitrc
。 在我的.xinitrc
我使用/usr/bin/mywm
启动窗口管理器。 现在,如果我杀了我的WM(为了测试其他WM),X也会终止,因为.xinitrc
脚本到达了EOF。 所以我在.xinitrc
的末尾加入了这个:
while true; do sleep 10000; done
这样,如果我杀死我的WM,X将不会终止。 现在我的问题是:我如何做一个无限的睡眠而不是循环睡眠? 有没有一个命令可能会让脚本冻结?
最好的祝福
TL; DR: sleep infinity
实际上睡眠允许的最大时间,这是有限的。
想知道为什么这个没有记录在任何地方,我懒得读一下GNU coreutils的源代码 ,我发现它大致执行如下:
- 在第一个参数中使用C stdlib的strtod将’infinity’转换为双精度。 所以,假设IEEE 754双精度,64位正无穷大值存储在
seconds
变量中。 - 调用
xnanosleep(seconds)
( 在gnulib中找到 ),这又调用dtotimespec(seconds)
(也在gnulib中)将double
从struct timespec
转换为struct timespec
。 struct timespec
只是一对整数:整数部分(以秒为单位)和小数部分(以纳秒为单位)。 天真地将正无穷大转换为整数会产生未定义的行为(参见C标准的第6.3.1.4节),所以它会截断为TYPE_MAXIMUM (time_t)
。TYPE_MAXIMUM (time_t)
的实际值不在标准中(甚至sizeof(time_t)
不是); 所以,为了举例,我们从最近的linux内核中选择x86-64。
这是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
。
即: sleep infinite
导致实际睡眠时间为9223372036854775807秒(10 ^ 11年)。 对于32位Linux系统( sizeof(long)
是4(32位)):2147483647秒(68年;另见2038年问题)。
编辑 :显然,调用的nanoseconds
函数不是直接的系统调用,而是依赖于操作系统的包装器(也在gnulib中定义 )。
结果有一个额外的步骤:对于HAVE_BUG_BIG_NANOSLEEP
为true
的某些系统,睡眠会被截断为24天,然后调用一个循环。 一些(或全部)Linux发行版就是这种情况。 请注意,如果配置时间测试成功( source ),则可能不会使用此包装。
特别是,这将是24 * 24 * 60 * 60 = 2073600 seconds
(加上999999999纳秒); 但为了尊重指定的总睡眠时间,这被称为循环。 因此,先前的结论仍然有效。
总之,所产生的睡眠时间不是无限的,但对于所有实际目的而言都足够高 ,即使由此产生的实际时间流逝不是便携式的; 这取决于操作系统和体系结构。
要回答原始问题,这显然已经足够好了,但如果出于某种原因( 非常资源受限的系统),您真的想要避免无用的额外倒计时器,我想最正确的选择是使用其他方法中描述的cat
方法答案。
sleep infinity
正是它的建议和工作没有猫虐待。
sleep infinity
看起来最优雅,但有时由于某种原因不起作用。 在这种情况下,您可以尝试其他阻止命令,例如cat
, read
, tail -f /dev/null
, grep a
等。
不要杀死窗口管理器,而应尝试使用--replace
或-replace
如果可用)运行新窗口。
也许这看起来很丑,但为什么不运行cat
,让它永远等待输入?
发送一个SIGSTOP到自己呢?
这应该暂停进程,直到收到SIGCONT。 你的情况是:从不。
kill -STOP "$$";
# grace time for signal delivery
sleep 60;
我最近有需要这样做。 我想出了下面这个函数,它允许bash永远睡觉而不需要调用任何外部程序:
snore()
{
[[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:)
read ${1:+-t "$1"} -u $_snore_fd || :
}
注意:我以前发布过这样一个版本,每次都会打开和关闭文件描述符,但是我发现在某些系统上每秒钟执行数百次最终会锁定。 因此,新解决方案在调用函数之间保留文件描述符。 无论如何,Bash会在退出时清理它。
这可以像/ bin / sleep一样调用,它会在请求的时间内休眠。 没有参数调用,它将永远挂起。
snore 0.1 # sleeps for 0.1 seconds
snore 10 # sleeps for 10 seconds
snore # sleeps forever
while :; do read; done
没有等待孩子睡觉的过程。