Python watchdog在os.system()上循环不止

1 投票
1 回答
1472 浏览
提问于 2025-04-18 15:11

我想写一个临时的小程序,让它在我每次修改latex文档后自动编译。

相关的代码如下:

class LatexCompiler(FileSystemEventHandler):
    def on_modified(self, event):
        if isinstance(event, watchdog.events.FileModifiedEvent):
            print event
            os.system("pdflatex Thesis.tex")

if __name__ == "__main__":
    path = sys.argv[1] if len(sys.argv) > 1 else '.'

    os.chdir("/path/to/my/tex/file")
    observer = Observer()
    observer.schedule(LatexCompiler(), path, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()

    observer.join()

一旦我加上了os.system(...)这一行,on_modified()这个方法就会在触发后无限循环。为了确保on_modified()只被调用一次,我把os.system()的调用去掉了,这样就只打印出了一行描述事件的信息。

那么,问题出在哪里呢?

1 个回答

2

事件处理器 on_modified() 会在监控的文件夹里,任何一个已有文件被修改时被调用。

我猜测,可能是 pdflatex 在生成过程中会创建一些临时文件,然后再对这些文件进行修改。或者也有可能是之前运行时生成的输出 pdf 文件被 pdflatex 修改了。不管怎样,这都会触发 on_modified() 这个处理器,接着它会再次运行 pdflatex(修改文件),这又会触发一次 on_modified() .... 你明白我的意思了吧。

你可以专门监控一组特定的文件,比如你的输入 tex 文件,只有当这些文件中的某一个被修改时,才触发 pdflatex。虽然还有一些细节需要整理,但下面的内容应该能给你一个大致的思路。

import os, time, sys
import watchdog.events
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer


class LatexCompiler(FileSystemEventHandler):
    def __init__(self, files, *args, **kwargs):
        super(LatexCompiler, self).__init__(*args, **kwargs)
        self._files = files
        print "LatexCompiler(): monitoring files %r" % self._files

    def on_modified(self, event):
        if (isinstance(event, watchdog.events.FileModifiedEvent) and
                event.src_path in self._files):
            print event
            os.system("pdflatex %s" % event.src_path)

if __name__ == "__main__":
    path = sys.argv[1] if len(sys.argv) > 1 else '.'

    observer = Observer()
    files = [os.path.join(path, f) for f in ['Thesis.tex', 'Resume.tex']]
    observer.schedule(LatexCompiler(files), path, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()

    observer.join()

撰写回答