Last active
July 3, 2026 19:26
-
-
Save ernstki/ba50c42ec22984afdf870030fdb84132 to your computer and use it in GitHub Desktop.
Watch for new files created matching a pattern, move them somewhere else with an auto-incrementing numerical prefix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| ## | |
| ## Authors: Kagi Quick, gemini/gemini-3.1-pro-preview, Kevin Ernst | |
| ## Date: 3 July 2026 | |
| ## Licence: WTFPL | |
| ## Homepage: https://gist.github.com/ernstki/ba50c42ec22984afdf870030fdb84132 | |
| ## | |
| ## Usage: python watchincrement.py "*.pdf" ~/Documents/00_TO_READ | |
| ## | |
| import re | |
| import os | |
| import sys | |
| import shutil | |
| import logging | |
| from fnmatch import fnmatch | |
| from watchdog.observers import Observer | |
| from watchdog.events import FileSystemEventHandler | |
| logging.basicConfig(level=logging.INFO) | |
| log = logging.getLogger(__name__) | |
| class Handler(FileSystemEventHandler): | |
| def __init__(self, watch_dir, dest, pattern): | |
| self.watch_dir = watch_dir | |
| self.dest = dest | |
| self.pattern = pattern | |
| os.makedirs(dest, exist_ok=True) | |
| def on_created(self, event): | |
| self._moveit(event) | |
| def on_modified(self, event): | |
| self._moveit(event) | |
| def _moveit(self, event): | |
| if event.is_directory: | |
| log.debug(f"{event} was a directory") | |
| return | |
| # The OS often queues multiple create/modify events for a single file operation. | |
| # If we already moved the file in a previous event, it will no longer exist here. | |
| if not os.path.exists(event.src_path): | |
| return | |
| if os.path.abspath(os.path.dirname(event.src_path)) != os.path.abspath(self.watch_dir): | |
| log.debug(f"{event} was not in watch_dir") | |
| return | |
| name = os.path.basename(event.src_path) | |
| if not fnmatch(name, self.pattern): | |
| log.debug(f"{event} didnt match pattern '{self.pattern}'") | |
| return | |
| existing = os.listdir(self.dest) | |
| new_num = 0 | |
| for f in existing: | |
| m = re.match(r"\[(\d{2})\]", f) | |
| if m: | |
| new_num = max(new_num, int(m.group(1))) | |
| new_num = new_num + 1 | |
| m = re.match(r'\[(\d{2})\] (.*)', name) | |
| suffix = m.group(2) if m else name | |
| target = os.path.join(self.dest, f"[{new_num:02d}] {suffix}") | |
| log.info(f"Moving {event.src_path} to {target}") | |
| shutil.move(event.src_path, target) | |
| if __name__ == "__main__": | |
| watch_dir = '.' | |
| pattern, dest_dir = sys.argv[1], sys.argv[2] | |
| observer = Observer() | |
| observer.schedule( | |
| Handler(watch_dir, dest_dir, pattern), watch_dir, recursive=False | |
| ) | |
| observer.start() | |
| try: | |
| while True: | |
| observer.join(1) | |
| except KeyboardInterrupt: | |
| observer.stop() | |
| observer.join() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment