Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 84 lines (59 sloc) 2.809 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#!/usr/bin/env python3

import argparse, os, glob, sys, operator, fnmatch

def pathwalk(path, filter, order, recurse=False):
    """walk along a path and stat the matching files"""
    entries = dict()

    for root, dirs, files in os.walk(path):
        for f in files:
            if filter and not fnmatch.fnmatch(f, filter):
                continue

            fullpath = os.path.join(root, f)
            entries[fullpath] = os.lstat(fullpath).st_mtime

        if not recurse: break

    return sorted(entries.items(), key=operator.itemgetter(1), reverse=order)

def print_each(*args):
    """print a filename plus the delimiter"""
    sys.stdout.write("%s%c" % args)
    return 0

def unlink_each(*args):
    """attempt to unlink a file"""
    try:
        os.unlink(args[0])
        return 0
    except OSError(errno, strerror):
        sys.stderr.write("%s: cannot unlink `%s': %s\n" % (sys.argv[0], args[0], 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='filter', 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.filter, 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()
Something went wrong with that request. Please try again.