将 docx 转换为 PDF 时两次 inotifywait 触发事件

Posted

技术标签:

【中文标题】将 docx 转换为 PDF 时两次 inotifywait 触发事件【英文标题】:inotifywait triggering event twice while converting docx to PDF 【发布时间】:2017-09-29 05:36:05 【问题描述】:

我有带有 inotifwait 的 shell 脚本设置如下:

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/

这里还有什么问题?

问候

【问题讨论】:

我看了一下strace结果,都是soffice.bin本身的close,第一个是将temp pdf结果文件复制到目的地,第二个只是检查它的统计信息,必须挖掘深入了解java源代码。但是为什么这会困扰你? 感谢@georgexsh 的回复。实际上,有一些与此触发器绑定的 COPY-TO-CLOUD 功能正在进行。因此,文件被复制了两次,其他一些内务工作同时进行。 @JatinDhoot 你在寻找什么样的答案? @feast - 如果从 soffice 生成 PDF,我想只触发一次通知而不是两次。谢谢。 @JatinDhoot 如果没有包装代码,您将无法做到这一点,因为文件本身似乎被写入了两次 georgexsh straced 【参考方案1】:

它被触发了两次,因为这就是 soffice 内部的行为方式。 有一天它可能会开始写它 10 次,并在一次运行期间在这些写之间执行sleep 2,我们的程序不能,我相信不应该预测它并依赖它。

所以我会尝试从不同的角度解决问题 - 让我们将转换后的文件放入临时目录,然后将其移动到目标目录,如下所示:

soffice --headless --convert-to pdf:writer_pdf_Export &lt;path&gt;/upload/somedoc.docx --outdir &lt;path&gt;/tempdir/ &amp;&amp; mv &lt;path&gt;/tempdir/somedoc.pdf &lt;path&gt;/upload/

并按以下方式使用inotifywait

inotifywait -r -e moved_to  -m "<path>/upload" --format '%f##@@##%e##@@##%w'

优点是不再依赖soffice的内部逻辑。 如果您无法调整生成 pdf 文件的脚本的行为,那么您确实需要求助于@Tarun 建议的解决方法。

【讨论】:

【参考方案2】:

我认为您不能这样控制外部程序。但我假设您将此输出用于管道,然后将其输入到其他地方。在这种情况下,您可以避免在几秒钟内连续发生的事件

所以我们将%T 添加到--format--timefmt "%s" 以获得纪元时间。以下是更新后的命令

$ 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 完成的,每秒多次。正如你所看到的,第二个甚至被跳过了。 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($0,a,delimeter) ENDprint a[2]')
  EVENT=$(echo "$line" | awk -v delimeter="$DEL" 'split($0,a,delimeter) ENDprint 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"

在您的实际脚本中,如果您将禁用 echo,这只是用于演示目的

【讨论】:

感谢塔伦的努力。我会试一试,让你知道。问候

以上是关于将 docx 转换为 PDF 时两次 inotifywait 触发事件的主要内容,如果未能解决你的问题,请参考以下文章

python模块将doc/pdf/docx/rtf格式转换为文本[重复]

PHP - Laravel - 将 Docx 转换为 PDF

使用 LibreOffice / OpenOffice 将 docx 转换为 pdf

以编程方式将 Word (docx) 转换为 PDF

使用 jodconverter 和 OpenOffice 将 doc/docx 转换为 pdf

使用 Unoconv 将 docx 转换为 pdf 时出错