测试文件存在时出现意外结果

时间:2017-02-16 11:06:11

标签: bash vim

让我们假设我们有一个空文件夹,我们在其中创建以下Bash脚本:

String example = "Here you can have anything";

基本上,它等待修改/移动/创建/删除该目录中的文件,然后,如果文件#!/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!文件并运行Bash脚本。在脚本运行的情况下,如果我使用Vim编辑asdf.txt并对其进行更改,那么我可以看到asdf.txt检测到CREATE事件,但我得到的唯一输出是{{1 }}。这是为什么?对于我尝试过的其他编辑来说,情况并非如此。

请注意,如果我在inotifywait和文件测试之间添加一个小延迟,它就可以正常工作:

NO!

有没有办法在用Vim编辑文件后测试文件,而不必在脚本中添加任意延迟?

更新

这与Vim的交换文件有关。事实上,如果您编辑inotifywait并告诉Vim避免创建交换文件,则不会发生这种情况。

但是,此脚本将由最终用户运行,我不能指望它们具有任何特定的Vim配置(也不要求它们避免交换文件或更改交换文件的默认目录)。

我怀疑应该有一种方法可以使用[...] inotifywait ... sleep 0.01 if [-f 'asdf.txt' ]; ... [...] 中的vimrc选项,但我还没有成功使用它(尝试使用--exclude)。

2 个答案:

答案 0 :(得分:1)

不要将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来保护标准输入,以防你的“某事”需要用户输入。

一个优点是,您将接收在“需要一些时间”的事情发生时发生的事件。如果您想避免接收事件的延迟,您可能希望在后台执行“某事”(使用&)。

答案 1 :(得分:0)

在保存对文件的更改时,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。
  • 实际上原始文件移动到备份文件中(这就是测试可能失败的原因),然后创建一个新文件来替换原始文件。

创建适当的规则并在选择事件inotifywait时更具限制性将触发,我们可以使用:

inotifywait --exclude ".*\.(swp|swx)|4913|.*~" -r -e modify,moved_to,create,delete $(dirname $0)

请注意,我们已经忘记了moved_from个事件。

这可以与Fred's answer结合使用,将Vim编辑视为特殊情况(即:当我们第一次看到正在创建的4913文件时。)