jfg*_*956 25 bash sleep shell-script
我知道我可以通过执行以下操作来等待条件在 bash 中变为真:
while true; do
test_condition && break
sleep 1
done
Run Code Online (Sandbox Code Playgroud)
但它在每次迭代(睡眠)时创建 1 个子流程。我可以通过以下方式避免它们:
while true; do
test_condition && break
done
Run Code Online (Sandbox Code Playgroud)
但它使用大量 CPU(忙等待)。为了避免子进程和忙于等待,我想出了下面的解决方案,但我发现它很难看:
my_tmp_dir=$(mktemp -d --tmpdir=/tmp) # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo # Open the fifo for reading and writing.
while true; do
test_condition && break
read -t 1 -u 3 var # Same as sleep 1, but without sub-process.
done
exec 3<&- # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir # Cleanup, could be done in a trap.
Run Code Online (Sandbox Code Playgroud)
注意:在一般情况下,我不能在没有read -t 1 varfifo 的情况下简单地使用,因为它会消耗 stdin,如果 stdin 不是终端或管道,它将无法工作。
我可以以更优雅的方式避免子流程和忙于等待吗?
Ans*_*ann 21
在较新版本bash(至少 v2)中,可以enable -f filename commandname在运行时(通过)加载内置函数。许多此类可加载的内置函数也随 bash 源一起分发,并且sleep属于其中之一。当然,可用性可能因操作系统而异(甚至机器与机器)。例如,在 openSUSE 上,这些内置程序通过包bash-loadables.
Gil*_*il' 10
在内部循环中创建大量子流程是一件坏事。sleep每秒创建一个进程是可以的。没有什么问题
while ! test_condition; do
sleep 1
done
Run Code Online (Sandbox Code Playgroud)
如果你真的想避免外部进程,你不需要保持fifo打开。
my_tmpdir=$(mktemp -d)
trap 'rm -rf "$my_tmpdir"' 0
mkfifo "$my_tmpdir/f"
while ! test_condition; do
read -t 1 <>"$my_tmpdir/f"
done
Run Code Online (Sandbox Code Playgroud)
我最近需要这样做。我想出了以下函数,它可以让 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 || :
}
Run Code Online (Sandbox Code Playgroud)
注意:我之前发布了一个每次都会打开和关闭文件描述符的版本,但我发现在某些系统上每秒执行数百次最终会锁定。因此,新解决方案在函数调用之间保留文件描述符。无论如何,Bash 会在退出时清理它。
这可以像 /bin/sleep 一样调用,它会在请求的时间内休眠。不带参数调用,它将永远挂起。
snore 0.1 # sleeps for 0.1 seconds
snore 10 # sleeps for 10 seconds
snore # sleeps forever
Run Code Online (Sandbox Code Playgroud)