Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active July 3, 2026 19:26
Show Gist options
  • Select an option

  • Save ernstki/ba50c42ec22984afdf870030fdb84132 to your computer and use it in GitHub Desktop.

Select an option

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
#!/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