让我们假设我们有一个空文件夹,在其中创建以下bash脚本:
#!/bin/bash
while true; do
inotifywait -r -e modify,move,create,delete $(dirname $0)
if [ -f 'asdf.txt' ]; then
echo "YES!"
else
echo "NO!"
fi
# Do something that takes some time...
sleep 0.1
done
基本上,它等待该目录中的文件进行修改/移动/创建/删除,然后,如果文件asdf.txt
存在,则将YES!
打印为输出。
现在让我们创建该asdf.txt
文件并运行BASH脚本。在运行脚本的情况下,如果我用VIM编辑asdf.txt
并为其编写更改,那么我可以看到inotifywait
检测到的CREATE
事件,但我唯一获得的输出是NO!
。这是为什么?我尝试过的其他编辑不会发生这种情况。
请注意,如果我在inotifywait
和文件测试之间添加一个小延迟,则可以正常工作:
[...]
inotifywait ...
sleep 0.01
if [-f 'asdf.txt' ]; ...
[...]
在文件刚刚使用VIM进行编辑后而无需在脚本中添加任意延迟之后,是否可以测试该文件?
更新
这与VIM的交换文件有关。实际上,如果您编辑vimrc
并告诉VIM避免创建交换文件,这将不会发生。
但是,此脚本将由最终用户运行,我不能期望他们具有任何特定的VIM配置(也不要求它们避免交换文件或更改交换文件默认目录)。
我怀疑应该使用inotifywait
中的--exclude
选项有一种方法,但是我尚未成功使用它(使用--exclude ".*.swp"
尝试)。
,而不是将inotifywait
放入循环中,使用监视选项并将输出输送到循环中,例如:
while IFS= read -r -u 5 EVENT
do
(PARSE EVENT)
if [ (I am interested in that file) ]; then
echo "YES!"
else
echo "NO!"
fi
# Do something that takes some time...
# Do not sleep
done 5< <(inotifywait -m ....)
上面的代码使用文件描述符5来保护标准输入,以防您的"某物"需要用户输入。
一个优点是,您将收到在发生"需要一些时间"的事件时发生的事件。如果要避免接收事件的延迟,您可能需要在后台执行"某物"(使用&
)。
vim实际上在保存到文件时会做很多事情:
./ CREATE 4913
./ DELETE 4913
./ MOVED_FROM asdf.txt
./ MOVED_TO asdf.txt~
./ CREATE asdf.txt
./ MODIFY asdf.txt
./ DELETE asdf.txt~
./ MODIFY .asdf.txt.swp
[...]
实际上可能会期望有些(例如创建和编辑交换和备份文件)。但是有些可能有点违反直觉:
- 它首先创建并破坏测试文件
4913
,以尝试验证它可以在您看到文件的目录中创建文件并设置UID/GID。 - 它实际上 moves 将原始文件移至备份文件(这就是测试可能会失败的原因),然后创建一个新文件来替换原始文件。
在选择事件inotifywait
会触发时,创建适当的规则并更加限制,我们可以使用:
inotifywait --exclude ".*.(swp|swx)|4913|.*~" -r -e modify,moved_to,create,delete $(dirname $0)
请注意,我们失去了moved_from
事件的跟踪。
这可以与弗雷德(Fred)的答案相结合,以将VIM编辑视为特殊情况(即:当我们首次看到4913
文件时)。