Usage
Basic search
find_files() walks a directory tree and yields matching pathnames:
from findtools.find_files import find_files, Match
for pathname in find_files('/var/log', Match(filetype='f', name='*.log')):
print(pathname)
Without a matcher, every file and directory in the tree is yielded:
everything = list(find_files('/etc'))
File types
Match(filetype=...) accepts the same single-letter flags as
find -type, or their long names:
| Flag | Long name | Matches |
|---|---|---|
f |
file |
regular files |
d |
directory |
directories |
l |
link |
symbolic links |
directories = find_files('/tmp', Match(filetype='d'))
symlinks = find_files('/usr/local/bin', Match(filetype='l'))
Name patterns
Three kinds of name patterns are understood:
# 1. Shell wildcard (fnmatch) — like find -name
Match(name='*.tar.gz')
# 2. Regular expression as a /slash-wrapped/ string
Match(name=r'/\d{4}-\d{2}-\d{2}\.log/')
# 3. A pre-compiled regular expression object
import re
from findtools.find_files import MatchAllPatternsAndTypes
MatchAllPatternsAndTypes(names=[re.compile(r'backup_\d+')])
Note
Patterns are matched against the basename of each entry, not the
full path — the same as find -name.
Combining conditions: all vs any
MatchAllPatternsAndTypes requires every condition to hold,
MatchAnyPatternsAndTypes is satisfied by any of them:
from findtools.find_files import (
find_files,
MatchAllPatternsAndTypes,
MatchAnyPatternsAndTypes,
)
# Files whose name starts with "1" AND ends with "1"
strict = MatchAllPatternsAndTypes(filetypes=['f'], names=['1*', '*1'])
# Anything that is a file OR a directory, named "*.bak" OR "*.tmp"
loose = MatchAnyPatternsAndTypes(
filetypes=['f', 'd'],
names=['*.bak', '*.tmp'],
)
stale = find_files('/var/cache', loose)
Match is a convenience shortcut for a single filetype and/or a single
name pattern with all semantics.
Collectors
By default each match yields its full pathname. Pass a different
collect callable to shape the results — for example, the bundled
collect_size:
from findtools.find_files import find_files, Match, collect_size
for pathname, size in find_files('/var/log',
Match(filetype='f', name='*.log'),
collect=collect_size):
print('%s: %d bytes' % (pathname, size))
A collector is any callable (root, name) -> result:
import os
def collect_mtime(root, name):
pathname = os.path.join(root, name)
return pathname, os.path.getmtime(pathname)
Non-recursive search
Limit the search to the top level of a directory, like
find -maxdepth 1:
top_level_only = find_files('/opt', Match(filetype='d'), recursive=False)
Helpers in findtools.core
from findtools.core import touch, change_dir
# Create an empty file / update its timestamps, like the touch command
touch('/tmp/marker')
# Temporarily change the working directory
with change_dir('/tmp', 'build'):
... # cwd is /tmp/build here
# cwd is restored afterwards