将 docx 转换为 PDF 时 inotifywait 触发事件两次
inotifywait triggering event twice while converting docx to PDF
我有 shell 脚本,inotifwait 设置如下:
inotifywait -r -e close_write,moved_to -m "<path>/upload" --format '%f##@@##%e##@@##%w'
监视目录中有一些 docx 文件,一些脚本通过以下命令将 docx 转换为 PDF:
soffice --headless --convert-to pdf:writer_pdf_Export <path>/upload/somedoc.docx --outdir <path>/upload/
不知何故,一旦生成PDF,事件就会被触发两次。参赛作品如下:
somedoc.pdf##@@##CLOSE_WRITE,CLOSE##@@##<path>/upload/
somedoc.pdf##@@##CLOSE_WRITE,CLOSE##@@##<path>/upload/
这里还有什么问题?
此致
我不认为你可以这样控制外部程序。但我假设您正在将此输出用于管道,然后将其输入其他地方。在这种情况下,您可以避免在几秒内连续发生的事件
所以我们在--format
和--timefmt "%s"
上加上%T
得到纪元时间。下面是更新后的命令
$ inotifywait -r -e close_write,moved_to --timefmt "%s" -m "/home/vagrant" --format '%f##@@##%e##@@##%w##T%T' -q | ./process.sh
test.txt##@@##CLOSE_WRITE,CLOSE##@@##/home/vagrant/
Skipping this event as it happend within 2 seconds. TimeDiff=2
test.txt##@@##CLOSE_WRITE,CLOSE##@@##/home/vagrant/
这是通过使用 touch test.txt
完成的,每秒多次。正如您所看到的,第二个 even 被跳过了。 process.sh
是一个简单的 bash 脚本
#!/bin/bash
LAST_EVENT=
LAST_EVENT_TIME=0
while read line
do
DEL="##T"
EVENT_TIME=$(echo "$line" | awk -v delimeter="$DEL" '{split([=11=],a,delimeter)} END{print a[2]}')
EVENT=$(echo "$line" | awk -v delimeter="$DEL" '{split([=11=],a,delimeter)} END{print a[1]}')
TIME_DIFF=$(( $EVENT_TIME - $LAST_EVENT_TIME))
if [[ "$EVENT" == "$LAST_EVENT" ]]; then
if [[ $TIME_DIFF -gt 2 ]]; then
echo "$EVENT"
else
echo "Skipping this event as it happend within 2 seconds. TimeDiff=$TIME_DIFF"
fi
else
echo $EVENT
LAST_EVENT_TIME=$EVENT_TIME
fi
LAST_EVENT=$EVENT
done < "${1:-/dev/stdin}"
在您的实际脚本中,您将在 if 中禁用 echo
,这只是为了演示目的
它被触发了两次,因为这是 soffice 内部的行为方式。
有一天它可能会开始写入 10 次并在一次 运行 期间在这些写入之间执行 sleep 2
,我们的程序不能而且我相信不应该预料到它并依赖它。
所以我会尝试从不同的角度解决问题 - 让我们将转换后的文件放入一个临时目录,然后将其移动到目标目录,如下所示:
soffice --headless --convert-to pdf:writer_pdf_Export <path>/upload/somedoc.docx --outdir <path>/tempdir/ && mv <path>/tempdir/somedoc.pdf <path>/upload/
并按以下方式使用 inotifywait
:
inotifywait -r -e moved_to -m "<path>/upload" --format '%f##@@##%e##@@##%w'
好处是你不再依赖soffice的内部逻辑。
如果您无法调整生成 pdf 文件的脚本的行为,那么您确实需要求助于 @Ta运行 建议的解决方法。
我有 shell 脚本,inotifwait 设置如下:
inotifywait -r -e close_write,moved_to -m "<path>/upload" --format '%f##@@##%e##@@##%w'
监视目录中有一些 docx 文件,一些脚本通过以下命令将 docx 转换为 PDF:
soffice --headless --convert-to pdf:writer_pdf_Export <path>/upload/somedoc.docx --outdir <path>/upload/
不知何故,一旦生成PDF,事件就会被触发两次。参赛作品如下:
somedoc.pdf##@@##CLOSE_WRITE,CLOSE##@@##<path>/upload/
somedoc.pdf##@@##CLOSE_WRITE,CLOSE##@@##<path>/upload/
这里还有什么问题?
此致
我不认为你可以这样控制外部程序。但我假设您正在将此输出用于管道,然后将其输入其他地方。在这种情况下,您可以避免在几秒内连续发生的事件
所以我们在--format
和--timefmt "%s"
上加上%T
得到纪元时间。下面是更新后的命令
$ inotifywait -r -e close_write,moved_to --timefmt "%s" -m "/home/vagrant" --format '%f##@@##%e##@@##%w##T%T' -q | ./process.sh
test.txt##@@##CLOSE_WRITE,CLOSE##@@##/home/vagrant/
Skipping this event as it happend within 2 seconds. TimeDiff=2
test.txt##@@##CLOSE_WRITE,CLOSE##@@##/home/vagrant/
这是通过使用 touch test.txt
完成的,每秒多次。正如您所看到的,第二个 even 被跳过了。 process.sh
是一个简单的 bash 脚本
#!/bin/bash
LAST_EVENT=
LAST_EVENT_TIME=0
while read line
do
DEL="##T"
EVENT_TIME=$(echo "$line" | awk -v delimeter="$DEL" '{split([=11=],a,delimeter)} END{print a[2]}')
EVENT=$(echo "$line" | awk -v delimeter="$DEL" '{split([=11=],a,delimeter)} END{print a[1]}')
TIME_DIFF=$(( $EVENT_TIME - $LAST_EVENT_TIME))
if [[ "$EVENT" == "$LAST_EVENT" ]]; then
if [[ $TIME_DIFF -gt 2 ]]; then
echo "$EVENT"
else
echo "Skipping this event as it happend within 2 seconds. TimeDiff=$TIME_DIFF"
fi
else
echo $EVENT
LAST_EVENT_TIME=$EVENT_TIME
fi
LAST_EVENT=$EVENT
done < "${1:-/dev/stdin}"
在您的实际脚本中,您将在 if 中禁用 echo
,这只是为了演示目的
它被触发了两次,因为这是 soffice 内部的行为方式。
有一天它可能会开始写入 10 次并在一次 运行 期间在这些写入之间执行 sleep 2
,我们的程序不能而且我相信不应该预料到它并依赖它。
所以我会尝试从不同的角度解决问题 - 让我们将转换后的文件放入一个临时目录,然后将其移动到目标目录,如下所示:
soffice --headless --convert-to pdf:writer_pdf_Export <path>/upload/somedoc.docx --outdir <path>/tempdir/ && mv <path>/tempdir/somedoc.pdf <path>/upload/
并按以下方式使用 inotifywait
:
inotifywait -r -e moved_to -m "<path>/upload" --format '%f##@@##%e##@@##%w'
好处是你不再依赖soffice的内部逻辑。 如果您无法调整生成 pdf 文件的脚本的行为,那么您确实需要求助于 @Ta运行 建议的解决方法。