findSearch the filesystem by name, size, age, owner and more
find walks a directory tree live and tests every file against your conditions: name, type, size, age, owner, permissions. Then it prints, deletes or runs a command on each match. It's the tool behind disk cleanups, security audits and most 'do X to every file that...' jobs.
find [-H|-L] [PATH...] [EXPRESSION] (tests, operators and actions)You need to locate source files and config directories in an unfamiliar project.
findGNU findutils: walks the tree and evaluates the expression for every entry.
find opens each starting directory and walks it depth-first using the fts library: getdents() to read entries, then fstatat() on an entry when a test needs metadata (-type, -size, -mtime, -perm, -user). Tests that only need the name, like -name, are cheap; GNU find even skips the stat when the directory entry's d_type already gives the file type. The expression is evaluated left to right for each file with short-circuit logic: -a (AND, implied between tests) stops at the first false, -o (OR) at the first true, so put cheap and selective tests first. With no action, -print is implied. -prune stops descent into a directory; -xdev stays on one filesystem; -maxdepth limits depth. -exec CMD {} \; forks one process per file, while -exec CMD {} + packs as many names as fit into each command line, like xargs. -delete implies -depth so contents are removed before their directory. Because find reads the live filesystem, results are always current but large trees cost real I/O.
find visits every entry under the start path, evaluates the tests left to right, and runs the action only on matches.
find /var/log -name '*.gz' -mtime +14 -exec rm {} +. The pattern is quoted, so find receives it untouched.
-name / -inameMatch the base name by glob (case-insensitive with -iname)-path / -regexMatch the whole path by glob / regular expression-type f|d|lRegular file, directory, symlink (also s, p, b, c)-size +100MSize larger (+), smaller (-) or exactly; units c k M G-mtime +7 / -mmin -30Modified more than 7 days ago / less than 30 minutes ago-newer FILE / -newermt DATEModified after a reference file / a date-user / -groupOwned by a user or group-perm -4000 / -perm -o+wHas all these bits: setuid / world-writable-emptyEmpty files and empty directories-maxdepth N / -mindepth NLimit how deep find goes-pruneDon't descend into the matched directory-xdevDon't cross into other filesystems (/proc, NFS, other disks)-exec CMD {} + / \;Run a command on matches: batched (+) or one per file (\;)-delete / -print0Delete matches / print NUL-separated names for xargs -0find . -name *.logThe shell expands *.log first. With several matches find errors out ('paths must precede expression'); with one, it silently searches only for that name.
find . -name '*.log'find /var/log -delete -name '*.tmp'The expression is evaluated in order: -delete comes first and is always true, so find deletes everything it visits before -name is checked.
find /var/log -name '*.tmp' -delete (actions last; test with -print first)find . -name a -o -name b -exec rm {} +AND binds tighter than OR, so -exec applies only to -name b.
find . \( -name a -o -name b \) -exec rm {} +find . -name '*.log' | xargs rmNames with spaces or newlines are split into wrong arguments, deleting the wrong files or failing.
find . -name '*.log' -print0 | xargs -0 rm (or simply -delete)find / -size +1G on a server with NFS mountsfind descends into every mount, including slow network shares and /proc, taking ages.
find / -xdev -size +1G (stay on one filesystem)Try these on a Linux machine of your own. Each task has a hint and a solution.
Find the big backup file mentioned in ~/data/notes.txt: the only file over 50 MB under ~/data.
List all .gz files under ~/logs and /var/log/app, hiding permission errors.
Count how many .js files are in ~/app.
Find every file in your home directory modified in the last 60 minutes, without descending into ~/data/archive.
Find world-writable files in your home. Then fix the one you find so only you can read and write it.
findSearch the filesystem by name, size, age, owner and more
find walks a directory tree live and tests every file against your conditions: name, type, size, age, owner, permissions. Then it prints, deletes or runs a command on each match. It's the tool behind disk cleanups, security audits and most 'do X to every file that...' jobs.
find [-H|-L] [PATH...] [EXPRESSION] (tests, operators and actions)You need to locate source files and config directories in an unfamiliar project.
findGNU findutils: walks the tree and evaluates the expression for every entry.
find opens each starting directory and walks it depth-first using the fts library: getdents() to read entries, then fstatat() on an entry when a test needs metadata (-type, -size, -mtime, -perm, -user). Tests that only need the name, like -name, are cheap; GNU find even skips the stat when the directory entry's d_type already gives the file type. The expression is evaluated left to right for each file with short-circuit logic: -a (AND, implied between tests) stops at the first false, -o (OR) at the first true, so put cheap and selective tests first. With no action, -print is implied. -prune stops descent into a directory; -xdev stays on one filesystem; -maxdepth limits depth. -exec CMD {} \; forks one process per file, while -exec CMD {} + packs as many names as fit into each command line, like xargs. -delete implies -depth so contents are removed before their directory. Because find reads the live filesystem, results are always current but large trees cost real I/O.
find visits every entry under the start path, evaluates the tests left to right, and runs the action only on matches.
find /var/log -name '*.gz' -mtime +14 -exec rm {} +. The pattern is quoted, so find receives it untouched.
-name / -inameMatch the base name by glob (case-insensitive with -iname)-path / -regexMatch the whole path by glob / regular expression-type f|d|lRegular file, directory, symlink (also s, p, b, c)-size +100MSize larger (+), smaller (-) or exactly; units c k M G-mtime +7 / -mmin -30Modified more than 7 days ago / less than 30 minutes ago-newer FILE / -newermt DATEModified after a reference file / a date-user / -groupOwned by a user or group-perm -4000 / -perm -o+wHas all these bits: setuid / world-writable-emptyEmpty files and empty directories-maxdepth N / -mindepth NLimit how deep find goes-pruneDon't descend into the matched directory-xdevDon't cross into other filesystems (/proc, NFS, other disks)-exec CMD {} + / \;Run a command on matches: batched (+) or one per file (\;)-delete / -print0Delete matches / print NUL-separated names for xargs -0find . -name *.logThe shell expands *.log first. With several matches find errors out ('paths must precede expression'); with one, it silently searches only for that name.
find . -name '*.log'find /var/log -delete -name '*.tmp'The expression is evaluated in order: -delete comes first and is always true, so find deletes everything it visits before -name is checked.
find /var/log -name '*.tmp' -delete (actions last; test with -print first)find . -name a -o -name b -exec rm {} +AND binds tighter than OR, so -exec applies only to -name b.
find . \( -name a -o -name b \) -exec rm {} +find . -name '*.log' | xargs rmNames with spaces or newlines are split into wrong arguments, deleting the wrong files or failing.
find . -name '*.log' -print0 | xargs -0 rm (or simply -delete)find / -size +1G on a server with NFS mountsfind descends into every mount, including slow network shares and /proc, taking ages.
find / -xdev -size +1G (stay on one filesystem)Try these on a Linux machine of your own. Each task has a hint and a solution.
Find the big backup file mentioned in ~/data/notes.txt: the only file over 50 MB under ~/data.
List all .gz files under ~/logs and /var/log/app, hiding permission errors.
Count how many .js files are in ~/app.
Find every file in your home directory modified in the last 60 minutes, without descending into ~/data/archive.
Find world-writable files in your home. Then fix the one you find so only you can read and write it.