Skip to content

Instantly share code, notes, and snippets.

@falconindy
Created August 17, 2014 12:24
Show Gist options
  • Save falconindy/2437fc68cba422ed6c95 to your computer and use it in GitHub Desktop.
Save falconindy/2437fc68cba422ed6c95 to your computer and use it in GitHub Desktop.
Operate on the newest or oldest files in a directory tree
#!/usr/bin/env python
import argparse, os, glob, sys, operator, fnmatch
def stderr(*args):
print(*args, file=sys.stderr, end='')
def filter_files(files, filterpat, root=""):
entries = {}
for f in files:
if filterpat and not fnmatch.fnmatch(f, filterpat):
continue
fullpath = os.path.join(root, f)
entries[fullpath] = os.lstat(f).st_mtime
return entries
def pathwalk_recursive(path, filterpat):
entries = {}
for root, dirs, files in os.walk(path):
entries.update(filter_files(files, filterpat))
return entries
def pathwalk(path, filterpat, order, recurse=False):
"""walk along a path and stat the matching files"""
entries = {}
if recurse:
entries = pathwalk_recursive(path, filterpat)
else:
dirents = (f for f in os.listdir(path) if
os.path.isfile(os.path.join(path, f)))
entries = filter_files(dirents, filterpat)
return sorted(entries.items(), key=operator.itemgetter(1), reverse=order)
def print_each(*args):
"""print a filename plus the delimiter"""
stderr("%s%c" % args)
return 0
def unlink_each(*args):
"""attempt to unlink a file"""
try:
os.unlink(args[0])
return 0
except OSError as e:
stderr('%s: cannot unlink `%s\': %s' % (sys.argv[0], args[0], e.strerror))
return 1
def main():
parser = argparse.ArgumentParser(description='find the latest files in a directory',
epilog='path defaults to the current directory if unspecified')
parser.add_argument('-0', '--null', action='store_const', dest='delim', default='\n',
const='\0', help='null delimit output')
parser.add_argument('-r', '--recurse', action='store_true', dest='recurse', default=False,
help='recurse into directories')
parser.add_argument('-i', '--inverse', action='store_true', dest='inverse', default=False,
help='invert selection (all except latest count)')
parser.add_argument('-d', '--delete', action='store_const', dest='action', default=print_each,
const=unlink_each, help='delete each candidate instead')
parser.add_argument('-n', '--count', action='store', dest='count', default=1, type=int,
metavar='N', help='number of files to select')
parser.add_argument('-o', '--oldest', action='store_true', dest='reverse', default=False,
help='examine oldest files')
parser.add_argument('-f', '--filter', action='store', dest='filterpat', default=None,
metavar='PAT', help='filter files on glob pattern')
parser.add_argument('path', default='.', nargs='?', help='path to search')
opts = parser.parse_args()
if not os.path.exists(opts.path):
sys.stderr.write("error: path not found: %s\n" % opts.path)
sys.exit(os.EX_OSFILE)
files = pathwalk(opts.path, opts.filterpat, opts.reverse, opts.recurse)
if not files:
sys.exit(os.EX_DATAERR)
if opts.inverse:
candidates = files[0:len(files) - opts.count]
else:
candidates = files[-(opts.count):]
error = 0
for cand in candidates:
error += opts.action(cand[0], opts.delim)
sys.exit(bool(error))
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment