等待在 Bash 中创建文件 [英] Waiting for a file to be created in Bash
问题描述
我需要创建一个 bash 脚本来等待创建文件.该脚本将在 while 循环中使用 sleep 命令每隔 10 秒定期检查文件.等待时打印一条消息.创建文件后显示文件的内容.以下是我尝试实施的内容,但显然行不通.在这一点上,我不完全确定如何进行.
#!/bin/bash让文件=$1而 '( -f !/tmp/$1)'做睡 10echo "还在等待"完毕echo "文件 $1 的内容:"
这里的问题在于测试,而不是睡眠(正如最初的问题假设的那样).最小的修复可能如下所示:
while !测试 -f "/tmp/$1";做睡 10echo "还在等待"完毕
<小时>
记住 while
循环的语法:
while:while 命令;执行命令;完毕展开并执行 COMMANDS 只要最后一个命令在`while' 命令的退出状态为零.
也就是说,给while
的第一个参数,展开循环,是一个command;它需要遵循与任何其他 shell 命令相同的语法规则.
-f
作为 test
的参数是有效的——该命令也可以在名称 [
下访问,需要一个 ]
作为在该名称中使用时的最后一个参数——但它本身作为一个命令是无效的——并且当作为字符串的一部分传递时,它甚至不是一个 shell 词,可以 被解析为单个命令名称或参数.
当您将 '( -f !/tmp/$1)'
作为命令运行时,在引号内,shell 正在寻找具有该名称(包括空格)的实际命令.您的 PATH 中可能没有名为 '/usr/bin/( -f !/tmp/$1)'
的文件,也没有找到该名称的任何其他命令,因此它总是会失败-- 立即退出 while
循环.
顺便说一句——如果你愿意让你的代码特定于操作系统,除了使用 sleep
等待文件存在之外,还有其他方法.例如,考虑 inotify-tools
包中的 inotifywait
:
while !测试 -f "/tmp/$1";做echo "正在等待更改/tmp 的内容" >&2inotifywait --timeout 10 --event create/tmp >/dev/null ||{(( $? == 2 )) &&continue ## inotify exit status 2 表示超时已过期回声无法与 inotifywait 一起睡觉;进行无条件的 10 秒循环">&2睡 10}完毕
基于 inotify 的接口的好处是它在文件系统更改时立即返回,并且不会产生轮询开销(如果它阻止系统休眠,这可能特别重要).
<小时>顺便说一下,一些练习笔记:
- 在文件名中引用扩展(即
"/tmp/$1"
)可防止带有空格或通配符的名称被扩展为多个不同的参数. - 在
echo
命令上使用>&2
用于记录人类消费,使 stderr 可用于编程消费 let
用于数学,而不是通用赋值.如果你想使用"$file"
,那没有错——但赋值应该是file=$1
,没有前面的let
>.
I need to create a bash script to wait for a file to be created. The script will use sleep command inside a while loop to periodically check on a file every 10 seconds. Print out a message while waiting. Display the content of the file once the file is created. Below is what I have tried to implement and it obviously does not work. At this point, I'm not entirely sure how to proceed.
#!/bin/bash
let file=$1
while '( -f ! /tmp/$1)'
do
sleep 10
echo "still waiting"
done
echo "Content of the file $1:"
The problem here is with the test, not the sleep (as the original question hypothesized). The smallest possible fix might look as follows:
while ! test -f "/tmp/$1"; do
sleep 10
echo "Still waiting"
done
Keep in mind the syntax for a while
loop:
while: while COMMANDS; do COMMANDS; done Expand and execute COMMANDS as long as the final command in the `while' COMMANDS has an exit status of zero.
That is to say, the first argument given to while
, expanding the loop, is a command; it needs to follow the same syntax rules as any other shell command.
-f
is valid as an argument to test
-- a command which is also accessible under the name [
, requiring a ]
as the last argument when used in that name -- but it's not valid as a command in and of itself -- and when passed as part of a string, it's not even a shell word that could be parsed as an individual command name or argument.
When you run '( -f ! /tmp/$1)'
as a command, inside quotes, the shell is looking for an actual command with exactly that name (including spaces). You probably don't have a file named '/usr/bin/( -f ! /tmp/$1)'
in your PATH or any other command by that name found, so it'll always fail -- exiting the while
loop immediately.
By the way -- if you're willing to make your code OS-specific, there are approaches other than using sleep
to wait for a file to exist. Consider, for instance, inotifywait
, from the inotify-tools
package:
while ! test -f "/tmp/$1"; do
echo "waiting for a change to the contents of /tmp" >&2
inotifywait --timeout 10 --event create /tmp >/dev/null || {
(( $? == 2 )) && continue ## inotify exit status 2 means timeout expired
echo "unable to sleep with inotifywait; doing unconditional 10-second loop" >&2
sleep 10
}
done
The benefit of an inotify-based interface is that it returns immediately upon a filesystem change, and doesn't incur polling overhead (which can be particularly significant if it prevents a system from sleeping).
By the way, some practice notes:
- Quoting expansions in filenames (ie.
"/tmp/$1"
) prevents names with spaces or wildcards from being expanded into multiple distinct arguments. - Using
>&2
onecho
commands meant to log for human consumption keeps stderr available for programmatic consumption let
is used for math, not general-purpose assignments. If you want to use"$file"
, nothing wrong with that -- but the assignment should just befile=$1
, with no precedinglet
.
这篇关于等待在 Bash 中创建文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!