JRC*_*JRC 6 shell-script inotify
我正在尝试使用 inotifywait 来观看文件夹(/shares/Photos),当它检测到添加到该文件夹中的 jpg 时,我需要将其大小调整到子目录($small_dir)中。在照片管理器下会有许多 jpg 子文件夹。
这棵树看起来像这样
shares
-Photos
-Folder 1
-Folder 2
.
.
.
Run Code Online (Sandbox Code Playgroud)
基本上,每当有人将图片复制到folder 1我需要创建一个新的子文件夹,然后调整图像大小并将较小的版本放入该文件夹中。
所以树会变成:
shares
-Photos
-Folder 1
-Resized
-Folder 2
.
.
.
Run Code Online (Sandbox Code Playgroud)
到目前为止我的代码:
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
Run Code Online (Sandbox Code Playgroud)
它基本上可以工作,但我要撞墙的是,如果我在Photos脚本运行时创建一个新的子文件夹,inotifywait 只会忽略它并且不执行任何操作。
我尝试替换close_write为create,但没有什么区别,我真的不知道从这里去哪里。
任何建议/帮助将不胜感激。
OP正在使用:
Run Code Online (Sandbox Code Playgroud)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)。同时,我正在纠正过滤以字符串或结尾的文件名的意图,不包括这些字符串,并可能改进对内部带有空格的目录的初始处理(和的影响,但稍后还有更多需要修复)。OP确实应该在脚本中用引号保护所有相关变量(不替换引号)。jpgjpegchanged_abssmall_dir{ }
代替:
Run Code Online (Sandbox Code Playgroud)inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |
和:
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}/
Run Code Online (Sandbox Code Playgroud)
尚未完全测试,但这就是想法。我什至不确定是否需要目录测试(看起来它从来没有发生过close_write事件),但这不会有什么坏处。
笔记
如果不清楚,则inotify_add_watch(2)必须为inotifywait检测到的每个目录创建事件执行操作 ( ),inotifywait必须尽快向此目录添加新的监视,因为它可能会丢失其中的后续事件(竞争条件)。它甚至记录在错误部分:
递归目录中存在竞争条件,观察代码 [...] 可能无法修复。
较新版本的inotifywait,当至少在内核 >= 5.9 上以 root(或足够特权)运行时,应该能够使用该fanotify(7)设施,但我无法设法让我的版本inotifywait使用它,尽管应该是编译支持并具有足够新的内核。在将要使用的系统上fanotify(7),结合该--filesystem选项,假设这可以消除必须为每个较新的目录执行操作的需要,并使 OP 的方法基于过滤工作--includei。