findfiles finds file system objects in a UNIX-like environment and lists them in time (of last modification
and/or access) order. It's been tested on on Linux, AIX and Cygwin.
But we already have find for that, right? Correct, but findfiles has more of a time focus and adheres
more closely to the traditional UNIX philosophy of "do one thing and do it well".
Simple findfiles Examples
findfiles always lists the objects in time sorted order. Here are some common use cases:
- List all the files in the /app directory tree that were modified less than 30 seconds ago:
findfiles -fr -m -30s /app
- List all the files in the Videos directory tree for files named '*.mpg' or "*.mp4' modified
less than 2 weeks ago and also the files in the Photos directory tree named '*.jpg' or "*.jpeg'
modified more than 1 month ago (all case insensitive) in verbose mode, reverse sort:
findfiles -vfr -iRm -2W -p '\.mp[g4]$' Videos -m +1M -p '\.jpg$|\.jpeg$' Photos
- List all the files in the /dblogs and /var/log directories modified later than lastlogfile was:
findfiles -f -M -lastlogfile /dblogs /var/log
findfiles classifies file system objects as one of these three types: (regular) files,
directories, and "other" (e.g., pipes, block specials, symbolic links, etc.)
The findfiles Usage Message
See toward the bottom of the findfiles usage message for more examples of how to use it:
$ findfiles
usage (version 2.1.1):
findfiles [OPTION]... [target|-t target]... [OPTION]... [target|-t target]...
Some OPTIONs require arguments. These are:
age : a +/- relative age value followed by a time unit
ERE : a POSIX-style Extended Regular Expression (pattern)
path : the pathname of a reference object (file, directory, etc.)
target : the pathname of an object (file, directory, etc.) to search
OPTIONs - can be toggled on/off (parsed left to right):
-d|--directories : directories (default off)
-f|--files : regular files (default off)
-o|--others : other files (default off)
-r|--recursive : recursive - traverse file trees (default off)
-i|--ignore-case : case insensitive pattern match - invoke before -p option (default off)
OPTIONs requiring an argument (parsed left to right):
-a|--acc-age [-|+]access_age : - for newer/=, [+] for older/= ages (no default)
-m|--mod-age [-|+]modification_age : - for newer/=, [+] for older/= ages (default 0s: any time)
-p|--pattern ERE : POSIX-style Extended Regular Expression (pattern) (default '.*')
-t|--target target_path : target path (no default)
-A|--acc-ref [-|+]acc_ref_path : - for newer, [+] for older ages (no default)
-D|--depth maximum_recursion_depth : maximum recursion traversal depth/level (default 10000)
-M|--mod-ref [-|+]mod_ref_path : - for newer, [+] for older ages (no default)
Flags - are 'global' options (and can NOT be toggled by setting multiple times):
-h|--help : display this help message
-n|--nanoseconds : in verbose mode, display the maximum resolution of the OS/FS - up to ns
-s|--seconds : display file ages in seconds (default D_hh:mm:ss)
-u|--units : display units: s for seconds, B for Bytes (default off)
-R|--reverse : Reverse the (time) order of the output (default off)
Verbosity: (May be specified more than once for additional information.)
-v|--verbose : also display modification time, age & size(B) (default 0[off])
Time units:
Y: Years M: Months W: Weeks D: Days
h: hours m: minutes s: seconds
Note: Specify Y & M with integer values. W, D, h, m & s can also take floating point values.
Examples of command line arguments (parsed left to right):
-f /tmp # files in /tmp of any age, including future dates!
-vfn -m -1M /tmp # files in /tmp modified <= 1 month, verbose output with ns
-f -m 1D -p '\.ant$' /tmp # files in /tmp ending in '.ant' modified >= 1 day ago
-fip a /tmp -ip b /var # files named /tmp/*a*, /tmp/*A* or /var/*b*
-rfa -3h src # files in the src tree accessed <= 3 hours ago
-dRp pat junk # directories named junk/*pat* - reverse sort
-rfM -/etc/hosts /lib # files in the /lib tree modified after /etc/hosts was
-vfm -3h / /tmp -fda 1h /var # files in / or /tmp modified <= 3 hours, and dirs (but
# NOT files) in /var accessed >= 1h, verbose output
findfiles Copyright (C) 2016-2019 James S. Crook
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under certain conditions.
This program is licensed under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or (at your option) any
later version (see <http://www.gnu.org/licenses/>).
Both findfiles and find?
- Yes! Because they do different things and both are incredibly useful!
- GNU find is a fantastic utility! It does an amazing number of things. When it comes to finding,
it does nearly everything - it's like 128 Swiss Army knives all bolted together.
But for things that findfiles does, find's command line syntax is rather complex
and unwieldy. That's when findfiles is useful.
- findfiles' output is always sorted by time in some way.
- Download findfiles from github.
More Complicated findfiles Examples
- View the all the files in the /tmp tree modified in the last 10 seconds and in the /var/tmp tree
accessed in the last 2 minutes - least recent files first:
$ view $(findfiles -Rfr -m -10s /tmp -a -2m /var/tmp)
- Remove all files in the /tmp and /var/tmp trees that were last modified 1 year ago or more.
(Obviously you shouldn't do this if you have files that might still be required after a year!)
$ rm $(findfiles -fr -m +1Y /tmp /var/tmp)
- No access or modification times have been specified, so the default value ('-m 0s') means all
possible modification times (including future times) and the default patter ('-p ".*"') meaning all
patterns.
$ findfiles -vf .
20160510_101641 0D_00:15:11 30 ./barfoo
20160510_101638 0D_00:15:14 30 ./foobar
20160510_101633 0D_00:15:19 30 ./bar
20160510_101630 0D_00:15:22 30 ./foo
- Same as the above example, but with reverse sort ('-R'), times displayed in seconds ('-s'),
and units (both 's' and 'B') displayed with the units option ('-u'):
$ findfiles -vfRsu .
20160510_101630 922s 30B ./foo
20160510_101633 919s 30B ./bar
20160510_101638 914s 30B ./foobar
20160510_101641 911s 30B ./barfoo
- Find all files in the current directory modified <= 6 months ago.
A verbosity of >= 2 shows the start time information (i:) line:
$ findfiles -vvf -m -6M .
i: target time: 1505260813.333995833s ~= Wed 13 Sep 2017 10:00:13 AEST
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= Tue 13 Mar 2018 11:00:13 AEDT
20180313_104138 0D_00:18:34 2675 ./bar
Note the hour difference (10 vs 11 hours) and
the time zone change (AEST vs AEDT) when looking
back 6 months. DST was not in effect then (Sep) and "now" (Mar) DST time is in effect (southern hemisphere!).
A verbosity of >= 2 when using time of last modification and/or access also shows the target time(s) and
the last modified/accessed time(s) newer/older than (in s.ns) information (i:) lines.
- The same as the example above, but this time with the display nanoseconds ('-n') flag as well:
$ findfiles -vvfn -m -6M .
i: target time: 1505260813.333995833s ~= Wed 13 Sep 2017 10:00:13 AEST
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= Tue 13 Mar 2018 11:00:13 AEDT
20171215_230124.407596237 87D_11:58:48.926399596 2675 ./bar
- The same as the previous example, but this time the timezone environment variable TZ
has been set to UTC. Note that no daylight savings time (DST) time is in effect and so
the hour and timezone values are unchanged:
$ export TZ=UTC; findfiles -vvfn -m -6M .
i: target time: 1505260813.333995833s ~= Wed 13 Sep 2017 00:00:13 UTC
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= Tue 13 Mar 2018 00:00:13 UTC
20171215_230124.407596237 87D_11:58:48.926399596 2675 ./bar
- Info line (i:) dates in other languages (French, in this case):
$ export TZ=UTC
$ export LANG=fr_FR.UTF-8
$ findfiles -vfn -m -6M .
i: target time: 1505260813.333995833s ~= mer. 13 sept. 2017 00:00:13 UTC
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= mar. 13 mars 2018 00:00:13 UTC
20171215_120124.407596237 87D_11:58:48.926399596 2675 ./bar
Advanced findfiles Examples
Be very careful when using the FF_ environment variables! Poor choices may elicit unfortunate
results!
- Display objects' times in ISO 8601 time format with the FF_DATETIMEFORMAT environment
variable:
$ export TZ=UTC
$ export FF_DATETIMEFORMAT='%04d-%02d-%02dT%02d:%02d:%02dZ'
$ findfiles -vf -m -6M .
2017-12-15T12:01:24Z 87D_11:58:48 2675 ./bar
- A verbosity of >= 3 shows objects' timestamps and age, both in s.ns:
$ export TZ=UTC
$ export FF_DATETIMEFORMAT='%04d-%02d-%02dT%02d:%02d:%02dZ'
$ findfiles -vvvvf -m -6M .
i: target time: 1505260813.333995833s ~= Wed 13 Sep 2017 00:00:13 UTC
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= Tue 13 Mar 2018 00:00:13 UTC
1513339284.407596237 = 2017-12-15T12:01:24Z 7559928.926399596 = 87D_11:58:48 2675 ./bar
i: FF_STARTTIME='1520899213.333995833' (default='Now')
i: FF_DATETIMEFORMAT='%04d-%02d-%02dT%02d:%02d:%02dZ' (default='%04d%02d%02d_%02d%02d%02d')
i: FF_AGEFORMAT='%7ldD_%02ld:%02ld:%02ld' (default)
A verbosity of >=4 shows the environment variables that can be configured, and their values.
This is displayed after the file output.
- Set the age format with environment variable FF_AGEFORMAT:
$ export TZ=UTC
$ export FF_DATETIMEFORMAT='%04d-%02d-%02dT%02d:%02d:%02dZ'
$ export FF_AGEFORMAT='%7ld Days, %02ld hours, %02ld minutes, %02ld seconds'
$ findfiles -vvf -m -6M .
i: target time: 1505260813.333995833s ~= Wed 13 Sep 2017 00:00:13 UTC
i: 181.00000D ~= 15638400.000000000s last modified after (newer than) target time ('6M')
i: start time: 1520899213.333995833s ~= Tue 13 Mar 2018 00:00:13 UTC
2017-12-15T12:01:24Z 87 Days, 11 hours, 58 minutes, 48 seconds 2675 ./bar
Notes
- The output of findfiles is time focused - time of last access and/or last modification.
Even if there is no time specified on the command line, the output is sorted by time.
- The default sort order is newest first (decreasing).
- findfiles parses (and processes) command line arguments (targets and options) in left to
right (L-R) order.
- Some command line options are flags that can be toggled on/off (parsed L-R).
- Some command line options require parameters that can be set and reset (parsed L-R).
- Some command line options are global - they cannot be toggled on/off.
- --long-options are supported, but getopt_long was not used because of the L-R requirement.
As a result, "--" does not work (i.e., not the way getopt_long handles it).
- As of version 2, findfiles uses the 'nanosecond' timestamp information (in addition to the
seconds information) to determine objects' ages and their sort order.
However, findfiles reads objects' access and modification times from the file system via OS
calls. These values will almost certainly not be accurate to the nanosecond, only to
the resolution the file system (and/or OS) provides.
- findfiles calculates an object's age by subtracting that object's last modification
(or access) time from the start time (normally 'now' - the time findfiles was started).
Both seconds and 'nanoseconds' for both of these times are used to determine this time
difference - the object's age. 'Nanoseconds' may be displayed (with the '-n' option).
If they are not, only the seconds value is displayed. That is, the age values are not
rounded to the nearest second.
- If findfiles is instructed to find some objects based on last modification time and
others based on last access time, the output will be sorted based whichever time (last
access or last modification) was requested for each object.
- Integer or floating point number(s) of weeks, days, hours, minutes or seconds may be
specified.
- Only integer numbers of years and months may be specified because years and
months vary in length.
- As with any command (even find), be extremely careful when calling rm or mv, e.g.:
rm $(findfiles -fr -m 1Y /tmp /var/tmp) !
findfiles might not return any files, so rm would have no argument!
- Under certain circumstances, findfiles reports negative (modification and/or access)
age(s) for objects. When findfiles starts, the first thing it does is record its
start time. It takes a finite amount of time to traverse the target(s). The more
objects to be traversed, the longer it takes to check them all. Any target object
that's modified and/or accessed after this start time will therefore be reported
as having a negative age. This is very likely to occur when searching very large
trees containing objects that are modified/accessed frequently. For example,
running findfiles with a target of '/' (the entire file system) will likely report
objects with negative ages in /proc and /sys. So don't be alarmed if you observe
this.
- Informational output lines (starting with 'i:') go to stderr, so it's a trivial
matter to separate them from the file list output, which goes to stdout.
- It's not possible to change the order of the values displayed using FF_DATETIMEFORMAT
and/or FF_AGEFORMAT. For example, one may not switch the order of day and month.
(See printf for further information on formatting.)
- findfiles uses 24 hour time everywhere except in the informational ('i:') output
lines - e.g., if LANG is en_US.UTF8. (YOSJ staff use 24 hour time whenever it's
available!)
- The FF_STARTTIME environment variable is intended primarily for testing and debugging.
Version 1.x.x - 1 second time resolution
Version 1.x.x info can be found here:
findfiles v1.x.x.