我正在尝试编写一个 shell 脚本,它将等待一个文件出现在/tmp
调用的目录中sleep.txt
,一旦找到该文件,程序将停止,否则我希望程序处于睡眠(挂起)状态,直到找到该文件。现在,我假设我将使用测试命令。所以,像
(if [ -f "/tmp/sleep.txt" ];
then stop
else sleep.)
我是编写 shell 脚本的新手,非常感谢任何帮助!
答案1
在Linux下,您可以使用inotify内核子系统有效地等待目录中文件的出现:
inotifywait -e create,moved_to,attrib --include '/sleep.txt$' -qq /tmp
# script execution continues ...
注意:我添加了该attrib
事件,以便touch /tmp/sleep.txt
在文件已存在时也进行注册。
如果 sleep.txt 显示与inotify等待调用,即在手表建立之前可能创建或触摸文件时 - 然后再也不会,之后 - 人们可以像这样扩展代码:
coproc inw {
LC_ALL=C inotifywait -e create,moved_to --include '/sleep.txt$' /tmp 2>&1
}
while IFS= read -r -u "${inw[0]}" line; do
if [ "$line" = "Watches established." ]; then
break
fi
done
if [ -f /tmp/sleep.txt ]; then
kill $inw_PID
else
wait
fi
# script execution continues ...
与固定时间间隔轮询相比,这种方法的优点
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# script execution continues ...
是你的进程休眠更多。使用 inotify 事件规范(例如,脚本)仅在创建或打开create,attrib
下面的文件时安排执行。/tmp
通过固定时间间隔轮询,您会浪费每个时间增量的 CPU 周期。
答案2
只需将您的测试放入while
循环中即可:
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# next command
答案3
inotifywait
到目前为止给出的一些基于 - 的方法存在一些问题:
- 他们无法找到
sleep.txt
首先作为临时名称创建然后重命名为sleep.txt
.moved_to
除了以下之外,还需要匹配事件create
- 文件名可以包含换行符,打印换行符分隔的文件名称不足以确定是否
sleep.txt
已创建。foo\nsleep.txt\nbar
例如,如果创建了一个文件怎么办? - 如果文件已创建怎么办前
inotifywait
手表已经启动并安装了吗?然后inotifywait
将永远等待已经存在的文件。您需要确保该文件尚不存在后手表已安装。 inotifywait
找到文件后,某些解决方案会继续运行(至少直到创建另一个文件为止)。
为了解决这些问题,你可以这样做:
sh -c 'echo "$$" &&
LC_ALL=C exec inotifywait -me create,moved_to --format=/%f/ . 2>&1' | {
IFS= read pid &&
while IFS= read -r line && [ "$line" != "Watches established." ]; do
: wait for watches to be established
done
[ -e sleep.txt ] || [ -L sleep.txt ] || grep -qxF /sleep.txt/ && kill "$pid"
}
sleep.txt
请注意,我们正在监视当前目录中的创建(因此您需要在示例中.
执行 before 操作)。cd /tmp || exit
当前目录永远不会改变,因此当该管道成功返回时,它就是sleep.txt
已创建的当前目录。
当然,您可以替换.
为/tmp
上面的内容,但是在inotifywait
运行时,/tmp
可能已重命名多次(不太可能/tmp
,但在一般情况下需要考虑)或在其上安装新的文件系统,因此当管道返回时,它可能不会是一个/tmp/sleep.txt
已经创建的,而是一个/new-name-for-the-original-tmp/sleep.txt
。在此期间还可能创建了一个新/tmp
目录,并且不会监视该目录,因此sleep.txt
不会检测到在那里创建的目录。
答案4
基于 maxschlepzig 接受的答案(以及来自接受的答案的想法)https://superuser.com/questions/270529/monitoring-a-file-until-a-string-is-found)我提出以下改进的(在我看来)答案,它也可以与超时一起使用:
# Enable pipefail, so if the left side of the pipe fails it does not get silently ignored
set -o pipefail
( timeout 120 inotifywait -e create,open --format '%f' --quiet /tmp --monitor & ) | while read i; do if [ "$i" == 'sleep.txt' ]; then break; fi; done
EXIT_STATUS=$?
if [ "${EXIT_STATUS}" == '124' ]; then
echo "Timeout happened"
fi
如果在给定超时内未创建/打开文件,则退出状态为 124(根据超时文档(手册页))。如果它被创建/打开,则退出状态为 0(成功)。
是的,inotifywait 以这种方式在子 shell 中运行,并且该子 shell 仅在发生超时或主脚本退出时(以先到者为准)才会完成运行。