inotifywait 忽略监视目录中的新文件夹

inotifywait 忽略监视目录中的新文件夹

我正在尝试使用 inotifywait 来观看文件夹(/shares/Photos),当它检测到添加到该文件夹​​中的 jpg 时,我需要将其大小调整到子目录($small_dir)中。在照片管理器下会有许多 jpg 子文件夹。

这棵树看起来像这样

shares
  -Photos
      -Folder 1
      -Folder 2
       .
       .
       .

基本上,每当有人将图片复制到folder 1我需要创建一个新的子文件夹,然后调整图像大小并将较小的版本放入该文件夹中。

所以树会变成:

shares
  -Photos
      -Folder 1
          -Resized
      -Folder 2
       .
       .
       .

到目前为止我的代码:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |
while read -r date time dir file; do
    changed_abs=${dir}${file}
    small_dir=${dir}${target}/
    
    printf "\nFile $changed_abs was changed or created\n  dir=$dir \n  file=$file \n  small_dir=$small_dir \n"
    
    # Check if the $small_directory exists, if not create it.
    if [ -d "$small_dir" -a ! -h "$small_dir" ]
    then
        echo "$small_dir found, nothing to do."
    else
        echo "Creating $small_dir"
        mkdir $small_dir
        chmod 777 $small_dir
    fi
    
    # Check to see if the file is in $small_dir, if it is, do nothing.  
    if [ "$dir" = "$small_dir" ]; then
        printf "\nFile is in the $small_dir folder, nothing to do\n"
    else
        printf "\nResizing file into the $small_dir folder\n"
        # Code to resize the image goes here.
    fi
        
done

它基本上可以工作,但我要撞墙的是,如果我Photos在脚本运行时创建一个新的子文件夹,inotifywait 只会忽略它并且不执行任何操作。

我尝试替换close_writecreate,但没有什么区别,我真的不知道从这里去哪里。

任何建议/帮助将不胜感激。

答案1

OP正在使用:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |

有关的文档--includei告诉(粗体强调我的):

--includei <pattern>

处理事件仅适用于文件名与指定 POSIX 正则表达式匹配的文件子集,不区分大小写。

这不是:“显示事件”而是“处理事件”。事实上,这意味着只有有关名称包含.jpg或的目录的事件.jpeg才会被处理。

发生但不匹配过滤器的目录创建事件将不会被处理,因此inotifywait不会调用inotify_add_watch(2)关于这个事件以及后来发生的任何事情。因此,该子目录中永远不会监视事件。

我找不到使用--includei或其他类似选项表达“仅针对这些正则表达式的处理事件,或者也与任何目录”。


更新: 建议解决方法

因此,让它工作的方法似乎必须在命令之外进行过滤。grep如果不是 tty,GNU将缓冲其输出,因此添加--line-buffered.

这将受到用户输入的影响(例如文件名中的空格)。为了缓解这种情况,/需要在目录和文件名之间使用分隔符(在文件名中无效)。由于目录部分方便地包含尾随/,因此只需删除格式字符串中的空格就足够了(以及进一步的变量处理和重用,例如changed_abs)。同时,我正在纠正过滤文件名的意图结尾与字符串jpgor jpeg, not包括这些字符串,并可能改进对内部有空间的目录的初始处理(changed_abs和的影响,small_dir但稍后还有更多需要修复)。 OP确实应该在脚本中用引号保护所有相关变量({ }不替换引号)。

代替:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |
while read -r date time dir file; do
    changed_abs=${dir}${file}
    small_dir=${dir}${target}/

和:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w%f' -e close_write /shares/Photos |
    grep --line-buffered -Ei '/[^/]*\.(jpg|jpeg)$' |
while read -r date time changed_abs; do
    [ -d "$changed_abs" ] && continue # a directory looking like a picture filename was written to: skip this event
    dir="${changed_abs%/*}/"
    file="${changed_abs##*/}"
    small_dir="${dir}${target}/"

尚未完全测试,但这就是想法。我什至不确定是否需要目录测试(看起来它从来没有发生close_write过事件),但这不会有什么坏处。


笔记

  • 如果不清楚,则inotify_add_watch(2)必须对inotifywait检测到的每个目录创建事件执行操作 ( ),inotifywait必须尽快地向此目录添加一个新的监视,因为它可能会丢失其中的以下事件(竞争条件)。它甚至记录在错误部分:

    递归目录中存在竞争条件,观察代码 [...] 可能无法修复。

  • 较新版本的inotifywait,当至少在内核 >= 5.9 上以 root(或足够特权)运行时,应该能够使用fanotify(7)设施,但我无法设法让我的版本inotifywait使用它,尽管应该在支持下编译并拥有足够新的内核。在将要使用的系统上fanotify(7),结合该--filesystem选项,假设这可以消除必须为每个较新的目录执行操作的需要,并使 OP 的方法基于过滤工作--includei

相关内容