我正在寻找一种可靠的方法来检测文件重命名并获取旧文件名和新文件名。这是我到目前为止所拥有的:
COUNTER=0;
inotifywait -m --format '%f' -e moved_from,moved_to ./ | while read FILE
do
if [ $COUNTER -eq 0 ]; then
FROM=$FILE;
COUNTER=1;
else
TO=$FILE;
COUNTER=0;
echo "sed -i 's/\/$FROM)/\/$TO)/g' /home/a/b/c/post/*.md"
sed -i 's/\/'$FROM')/\/'$TO')/g' /home/a/b/c/post/*.md
fi
done
它可以工作,但它假设您永远不会将文件移入或移出监视的文件夹。它还假设事件成对出现,首先是 moving_from,然后是 moving_to。我不知道这是否总是正确的(到目前为止有效)。
我读到 inotify 使用 cookie 来链接事件。 cookie 是否可以通过某种方式访问?由于缺少 cookie,我考虑使用时间戳将事件链接在一起。有什么关于以更可靠的方式从 FROM 到 TO 的提示吗?
答案1
我认为你的方法是正确的,并且跟踪 cookie 是执行此操作的一种可靠方法。然而,inotify-tools (3.14) 源代码中唯一cookie
被引用的地方是定义与struct
内核 API 相匹配的标头。
如果你喜欢生活在边缘,这个补丁(问题#72)完全适用于3.14并%c
为事件 cookie 添加十六进制格式说明符:
--- libinotifytools/src/inotifytools.c.orig 2014-10-23 18:05:24.000000000 +0100
+++ libinotifytools/src/inotifytools.c 2014-10-23 18:15:47.000000000 +0100
@@ -1881,6 +1881,12 @@
continue;
}
+ if ( ch1 == 'c' ) {
+ ind += snprintf( &out[ind], size-ind, "%x", event->cookie);
+ ++i;
+ continue;
+ }
+
if ( ch1 == 'e' ) {
eventstr = inotifytools_event_to_str( event->mask );
strncpy( &out[ind], eventstr, size - ind );
此更改修改的是libinotifytools.so
,而不是inotifywait
二进制文件。安装前测试:
LD_PRELOAD=./libinotifytools/src/.libs/libinotifytools.so.0.4.1 \
inotifywait --format="%c %e %f" -m -e move /tmp/test
Setting up watches.
Watches established.
40ff8 MOVED_FROM b
40ff8 MOVED_TO a
假设 MOVED_FROM 总是发生在 MOVED_TO 之前(确实如此,请参阅fsnotify_move()
,这是一个有序队列,虽然独立移动可能在脚本中,当您看到 MOVED_FROM 行(可能在按 ID 索引的关联数组中)时,您会缓存详细信息,并在看到具有匹配的一半信息的 MOVED_TO 时运行处理。
declare -A cache
inotifywait --format="%c %e %f" -m -e move /tmp/test |
while read id event file; do
if [ "$event" = "MOVED_FROM" ]; then
cache[$id]=$file
fi
if [ "$event" = "MOVED_TO" ]; then
if [ "${cache[$id]}" ]; then
echo "processing ..."
unset cache[$id]
else
echo "mismatch for $id"
fi
fi
done
(运行三个线程以将一对文件各洗牌 10,000 次,我从未见过任何乱序事件或事件交错。当然,这可能取决于文件系统和其他条件。)