我正在尝试使用 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_write
为create
,但没有什么区别,我真的不知道从这里去哪里。
任何建议/帮助将不胜感激。
答案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
)。同时,我正在纠正过滤文件名的意图结尾与字符串jpg
or 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
。