| |

LFCS 22 ๐Ÿง Finding Files โ€” find

find is the most powerful file-searching tool on Linux. It walks a directory tree, evaluates an expression against each file, and prints or acts on the files that match. Unlike locate, which searches a pre-built database, find searches the actual file system in real time, so it always reflects the current state. Unlike ls with the shell globs, which expands in the shell and is limited to a single directory, find recurses into the subdirectories and applies the full set of the matching criteria: the name, the type, the size, the permissions, the ownership, the timestamps, and the content metadata. The LFCS exam tests it as part of the “Search files and content” objective, and it is the foundation of the file-management skills.

The command’s structure is different from the other tools. It is find <path> <expression>, where the path is the directory to search and the expression is a combination of the options, the tests, and the actions. The expression is evaluated left to right, and it is composed with the implicit AND: find /var/log -name '*.log' -size +10M means “the files under /var/log whose name ends with .log AND whose size is greater than 10 MB.” The -o for the OR and the ! for the NOT change the logic, and the parentheses group the conditions. The expression is the language, and the tool is the interpreter.

The default action is -print, which writes the matching file’s path to standard output. The other actions are -delete, -exec, -execdir, -ok, and the -ls for the detailed listing. The -exec is the workhorse: it runs a command for each matching file, and the {} is the placeholder for the file’s path. The -exec ... + form batches the files into the fewest possible invocations, which is the significant performance improvement over the \; form. The LFCS scenarios include finding the files by the name, the size, and the modification time, and the -exec to act on them.

This chapter covers three areas. First, why find exists โ€” the real-time search problem and the expression language. Second, how to use the tests โ€” the -name, -type, -size, -mtime, -user, -perm, and the -newer tests. Third, the actions and the combinations โ€” the -exec, the -delete, the -print0, the -o and the !, and the patterns for the common scenarios. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the expression evaluation.

Key point: find <path> <expression> walks the directory tree and evaluates the expression against each file. The expression is a combination of the tests and the actions, composed with the implicit AND, the -o for the OR, and the ! for the NOT. The default action is -print. The -exec runs a command for each matching file, and the -exec ... + form batches the invocations. Always quote the patterns to prevent the shell expansion.


Why find exists

The real-time search problem. The locate command searches a database that is updated by the updatedb job, usually once a day. The result is fast but stale: a file created since the last update is not found. The find command searches the actual file system, so it always finds the current files. The trade-off is the speed: the find walks the tree, and the large trees take longer. For the critical searches where the currency matters, the find is the right tool .

The single-directory problem. The shell globs like *.log expand to the files in a single directory. They do not recurse into the subdirectories. The find recurses by default, so find /var/log -name '*.log' finds the log files in the entire tree, not just the top directory.

The metadata problem. The shell globs match the file names only. The find matches the names, the types, the sizes, the permissions, the ownership, and the timestamps. A search for the files larger than 100 MB, or the files modified in the last 7 days, or the files owned by a specific user, is a find expression. The metadata is the point.

The action problem. The find can act on the matching files, not just list them. The -delete removes them, the -exec runs a command for each one, and the -exec ... + batches the command. The pattern find /tmp -type f -mtime +30 -delete is the standard cleanup, and the pattern find /var/log -name '*.log' -exec gzip {} + is the standard log rotation.

The expression problem. The find expression is a small language. The tests are the predicates, the actions are the side effects, and the operators combine them. The -o is the OR, the ! is the NOT, and the parentheses group the subexpressions. The expression is evaluated left to right, and the implicit AND is between the adjacent terms. The understanding of the expression is the key to the complex searches.

The trade-off. The find is slower than the locate and the shell globs, and the expression syntax is more complex. The locate is the right tool for the quick name searches when the database is current, and the shell globs are the right tool for the simple patterns in the current directory. The find is the right tool when the recursion, the metadata, or the action is needed.


a. The tests

The tests are the predicates that the find evaluates against each file. The most common ones are the name, the type, the size, the time, the user, the group, and the permissions.

The name. The -name test matches the file’s base name against a pattern. The pattern uses the shell globs (*, ?, [...]), and it must be quoted to prevent the shell from expanding it.

find /var/log -name '*.log'
find . -name 'config.yaml'
find /etc -name '*.conf'

The -iname is the case-insensitive version. The -path matches the full path, and the -regex matches the path against a regular expression.

find /etc -iname '*.CONF'
find . -path '*/src/*.js'
find . -regex '.*\.\(jpg\|png\)'

The type. The -type test matches the file’s type: f for the regular file, d for the directory, l for the symbolic link, b for the block device, c for the character device, p for the pipe, and s for the socket.

find /var/log -type f
find /home -type d
find /usr/bin -type l

The size. The -size test matches the file’s size. The suffixes are c for the bytes, k for the kilobytes, M for the megabytes, and G for the gigabytes. The + is the greater than, the - is the less than, and the absence is the exact match.

find / -size +100M
find /var/log -size -1k
find . -size 512c

The size is rounded up to the unit, so -size 1M matches the files from 1 byte to 1 MB (in the GNU find), which is a common source of the confusion. The -size +1M is the clearer form.

The time. The -mtime, -atime, and -ctime tests match the modification, access, and change times in the days. The -mmin, -amin, and -cmin are the minutes. The + is the older than, the - is the newer than, and the absence is the exact.

find /var/log -mtime -7        # modified in the last 7 days
find /tmp -mtime +30           # modified more than 30 days ago
find /home -mmin -60           # modified in the last 60 minutes

The -newer test compares against a reference file:

find /etc -newer /etc/passwd
find . -newer /tmp/reference -type f

The user and the group. The -user and the -group tests match the owner and the group. The -nouser and the -nogroup match the files whose owner or group does not exist in the passwd or group database.

find /home -user alice
find / -group www-data
find / -nouser

The permissions. The -perm test matches the file’s permissions. The exact match is -perm 644, the “all the bits are set” is -perm -644, and the “any of the bits are set” is -perm /644.

find . -perm 644              # exactly 644
find . -perm -u+w             # the user write bit is set
find . -perm /u+x,g+x         # the user or group execute bit is set

The symbolic form uses the u, g, o, a for the user, group, other, and all, and the r, w, x for the read, write, and execute.


b. The actions

The default action is -print, which writes the matching file’s path to standard output. The other actions are the -delete, the -exec, the -execdir, the -ok, and the -ls.

The -print and -print0. The -print writes the path followed by a newline. The -print0 writes the path followed by a null character, which is the safe form for the file names that contain the newlines or the spaces. The -print0 is paired with the xargs -0.

find . -name '*.log' -print
find . -name '*.log' -print0 | xargs -0 rm

The -delete. The -delete removes the matching files. It is the shorthand for the -exec rm {} +, and it is faster because the find removes the files directly.

find /tmp -type f -mtime +30 -delete
find . -name '*.tmp' -delete

The -delete implies the -depth, which processes the directory’s contents before the directory itself. The order is important for the recursive deletion.

The -exec. The -exec runs a command for each matching file. The {} is the placeholder for the file’s path, and the command is terminated by the \; or the +.

find /var/log -name '*.log' -exec gzip {} \;
find /var/log -name '*.log' -exec gzip {} +

The \; runs the command once per file. The + runs the command once with as many files as the system allows, which is much faster. The {} must be the last argument before the \; or the +, and it must be quoted or escaped.

The -execdir is the variant that runs the command in the directory of the matching file, which is safer for the untrusted trees. The -ok is the variant that prompts for the confirmation before each command.

find . -name '*.sh' -execdir chmod +x {} +
find /tmp -name '*.tmp' -ok rm {} \;

The -ls. The -ls prints the detailed listing, similar to the ls -l. It is the shortcut for the -exec ls -l {} +.

find /etc -name '*.conf' -ls

c. The combinations and the patterns

The AND, the OR, and the NOT. The adjacent tests are the implicit AND. The -o is the OR, and the ! is the NOT. The parentheses group the subexpressions, and they must be escaped or quoted to prevent the shell from interpreting them.

find . -name '*.log' -size +10M              # the AND
find . -name '*.log' -o -name '*.txt'        # the OR
find . ! -name '*.log'                       # the NOT
find . \( -name '*.log' -o -name '*.txt' \) -size +1M  # the grouped OR with the AND

The precedence is the NOT, the AND, then the OR. The parentheses override the precedence, and they are the source of the most of the confusion.

The common patterns. The cleanup of the old files:

find /tmp -type f -mtime +30 -delete
find /var/log -name '*.log' -mtime +7 -exec gzip {} \;

The search by the size and the type:

find / -type f -size +100M -exec ls -lh {} \;
find /home -type f -size +1G

The search by the permissions:

find / -type f -perm -4000        # the setuid files
find / -type f -perm /o+w         # the world-writable files

The search by the owner:

find /home -user alice -type f
find / -nouser -o -nogroup

The combinations:

find /var/log -type f \( -name '*.log' -o -name '*.err' \) -mtime +7 -delete
find /home -type f -name '*.jpg' -size +5M -exec cp {} /backup/ \;

Complete Example Session

# ============================================
# PART 1: THE BASIC NAME SEARCH
# ============================================

find /var/log -name '*.log'
find . -name 'config.yaml'
find /etc -iname '*.conf'


# ============================================
# PART 2: THE TYPE SEARCH
# ============================================

find /var/log -type f
find /home -type d
find /usr/bin -type l


# ============================================
# PART 3: THE SIZE SEARCH
# ============================================

find / -size +100M
find /var/log -size -1k
find . -size 512c


# ============================================
# PART 4: THE TIME SEARCH
# ============================================

find /var/log -mtime -7
find /tmp -mtime +30
find /home -mmin -60
find /etc -newer /etc/passwd


# ============================================
# PART 5: THE USER AND THE PERMISSIONS
# ============================================

find /home -user alice
find / -group www-data
find / -nouser
find . -perm 644
find . -perm -u+w
find / -type f -perm -4000


# ============================================
# PART 6: THE -exec ACTION
# ============================================

find /var/log -name '*.log' -exec gzip {} \;
find /var/log -name '*.log' -exec gzip {} +
find /tmp -name '*.tmp' -exec rm {} \;
find . -name '*.sh' -exec chmod +x {} +


# ============================================
# PART 7: THE -delete ACTION
# ============================================

find /tmp -type f -mtime +30 -delete
find . -name '*.tmp' -delete


# ============================================
# PART 8: THE -print0 AND THE xargs
# ============================================

find . -name '*.log' -print0 | xargs -0 rm
find . -name '*.txt' -print0 | xargs -0 wc -l


# ============================================
# PART 9: THE AND, THE OR, AND THE NOT
# ============================================

find . -name '*.log' -size +10M
find . -name '*.log' -o -name '*.txt'
find . ! -name '*.log'
find . \( -name '*.log' -o -name '*.txt' \) -size +1M


# ============================================
# PART 10: THE LFCS PIPELINE
# ============================================

# Clean the old temporary files
find /tmp -type f -mtime +30 -delete

# Compress the old log files
find /var/log -name '*.log' -mtime +7 -exec gzip {} \;

# Find the large files
find / -type f -size +100M -exec ls -lh {} \;

# Find the setuid files
find / -type f -perm -4000 -ls

# Find the world-writable files
find / -type f -perm /o+w -ls

# Find the files owned by a user
find /home -user alice -type f

# Find the files modified in the last 7 days
find /var/log -type f -mtime -7

# Find the files newer than a reference
find /etc -newer /etc/passwd -type f

The ten parts show the basic name search, the type search, the size search, the time search, the user and the permissions, the -exec action, the -delete action, the -print0 and the xargs, the AND/OR/NOT, and the LFCS pipeline.


Quick Reference

The Basic Syntax

FormMeaning
find pathList all the files under the path
find path -name 'pattern'Match the name
find path -iname 'pattern'Case-insensitive name
find path -path 'pattern'Match the full path
find path -regex 'regex'Match the path against a regex

The Tests

TestMeaning
-type f/d/lThe file, directory, symlink
-size +100MThe size greater than 100 MB
-mtime -7Modified in the last 7 days
-mtime +30Modified more than 30 days ago
-mmin -60Modified in the last 60 minutes
-newer fileNewer than the reference
-user aliceOwned by the user
-group www-dataThe group
-nouserNo valid owner
-perm 644Exactly 644
-perm -u+wThe user write bit is set
-perm /o+wThe other write bit is set

The Actions

ActionMeaning
-printThe default; print the path
-print0The null-separated output
-lsThe detailed listing
-deleteRemove the matching files
-exec cmd {} \;Run the command per file
-exec cmd {} +Run the command with the batch
-execdirRun in the file’s directory
-okPrompt before each command

The Operators

OperatorMeaning
(adjacent)The AND
-oThe OR
!The NOT
\( ... \)The grouping

The Common Scenarios

ScenarioCommand
The old temp filesfind /tmp -type f -mtime +30 -delete
The old logsfind /var/log -name '*.log' -mtime +7 -exec gzip {} \;
The large filesfind / -type f -size +100M -ls
The setuid filesfind / -type f -perm -4000 -ls
The world-writablefind / -type f -perm /o+w -ls

Best Practices

โœ… Do This:

# Quote the patterns
find /var/log -name '*.log'                                               # โœ…
# Use the -exec ... + for the batch
find . -name '*.log' -exec gzip {} +                                      # โœ…
# Use the -print0 with the xargs
find . -name '*.log' -print0 | xargs -0 rm                                # โœ…
# Use the parentheses for the grouped OR
find . \( -name '*.log' -o -name '*.txt' \) -size +1M                     # โœ…
# Use the -mtime -7 for the recent files
find /var/log -mtime -7                                                   # โœ…
# Use the -type f to skip the directories
find /tmp -type f -delete                                                 # โœ…

โŒ Don’t Do This:

# Don't forget the quotes
find . -name *.log  # the shell expands *.log                             // โŒ
# Don't use the -exec with the \; for the large sets
find . -name '*.log' -exec gzip {} \;  # too slow                         // โŒ
# Don't use the -delete without the -type f
find /tmp -delete  # removes the directories too                          // โŒ
# Don't forget the parentheses escaping
find . ( -name '*.log' -o -name '*.txt' ) -size +1M  # the shell error    // โŒ
# Don't use the -exec without the {}
find . -exec ls \;  # the file is not passed                              // โŒ
# Don't use the -size 1M expecting the exact match
find . -size 1M  # matches 1 byte to 1 MB                                 // โŒ

Common Pitfalls

PitfallWhy It HappensFix
The pattern is expandedThe quotes are missingQuote the pattern
The -exec is slowThe \; is usedUse the +
The -delete removes the directoriesNo -type fAdd the -type f
The parentheses cause an errorThe shell interprets themEscape or quote
The -size 1M matches the small filesThe roundingUse the + or the -
The -mtime +30 is the wrong wayThe + and the - are confusedThe + is the older, the - is the newer
The xargs splits the spacesNo -print0Use the -print0 and the -0
The -exec replaces the wrong argumentThe {} is not the lastPut the {} last

Real-World Examples

1. The Name Search

find /var/log -name '*.log'

2. The Type Search

find /home -type d

3. The Size Search

find / -size +100M

4. The Time Search

find /var/log -mtime -7

5. The User Search

find /home -user alice

6. The Permission Search

find / -type f -perm -4000

7. The -exec

find /var/log -name '*.log' -exec gzip {} +

8. The -delete

find /tmp -type f -mtime +30 -delete

9. The -print0

find . -name '*.log' -print0 | xargs -0 rm

10. The LFCS Pipeline

find /var/log -type f -name '*.log' -mtime +7 -exec gzip {} +

Visual

The Expression Evaluation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE EXPRESSION EVALUATION                                   โ”‚
โ”‚                                                              โ”‚
โ”‚  find /var/log -name '*.log' -size +10M -mtime +7            โ”‚
โ”‚                                                              โ”‚
โ”‚  For each file under /var/log:                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  1. -name '*.log'  โ†’ does the name end with .log?    โ”‚    โ”‚
โ”‚  โ”‚  2. -size +10M     โ†’ is the size > 10 MB?            โ”‚    โ”‚
โ”‚  โ”‚  3. -mtime +7      โ†’ is it older than 7 days?        โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The adjacent tests are the implicit AND.            โ”‚    โ”‚
โ”‚  โ”‚  All three must be true.                             โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚    โ”‚                                                         โ”‚
โ”‚    โ”‚  The file matches all three                             โ”‚
โ”‚    โ–ผ                                                         โ”‚
โ”‚  The default action: -print                                  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  /var/log/app.log                                    โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The AND, OR, NOT

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE AND, OR, NOT                                            โ”‚
โ”‚                                                              โ”‚
โ”‚  THE AND (the implicit):                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' -size +10M                     โ”‚    โ”‚
โ”‚  โ”‚  โ†’ the name ends with .log AND the size > 10M        โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  THE OR:                                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' -o -name '*.txt'               โ”‚    โ”‚
โ”‚  โ”‚  โ†’ the name ends with .log OR the name ends with .txtโ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  THE NOT:                                                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . ! -name '*.log'                              โ”‚    โ”‚
โ”‚  โ”‚  โ†’ the name does NOT end with .log                   โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  THE GROUPING:                                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . \( -name '*.log' -o -name '*.txt' \) -size +1Mโ”‚   โ”‚
โ”‚  โ”‚  โ†’ (the name ends with .log OR the name ends with    โ”‚    โ”‚
โ”‚  โ”‚     .txt) AND the size > 1M                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  The precedence: the NOT, the AND, then the OR.              โ”‚
โ”‚  The parentheses override the precedence.                    โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The -exec Forms

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE -exec FORMS                                             โ”‚
โ”‚                                                              โ”‚
โ”‚  THE \; FORM (per file):                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' -exec gzip {} \;               โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  gzip app.log                                        โ”‚    โ”‚
โ”‚  โ”‚  gzip error.log                                      โ”‚    โ”‚
โ”‚  โ”‚  gzip access.log                                     โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The command is run once per file.                   โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  THE + FORM (the batch):                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' -exec gzip {} +                โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  gzip app.log error.log access.log                   โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The command is run once with the batch.             โ”‚    โ”‚
โ”‚  โ”‚  Much faster for the large sets.                     โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  The {} is the placeholder for the file's path.              โ”‚
โ”‚  It must be the last argument before the \; or the +.        โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The -print0 and the xargs

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE -print0 AND THE xargs                                   โ”‚
โ”‚                                                              โ”‚
โ”‚  WITHOUT the -print0:                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' | xargs rm                     โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The newline-separated output.                       โ”‚    โ”‚
โ”‚  โ”‚  A file name with a space is split.                  โ”‚    โ”‚
โ”‚  โ”‚  "my file.log" โ†’ "my" and "file.log"                 โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  WITH the -print0 and the -0:                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  find . -name '*.log' -print0 | xargs -0 rm          โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The null-separated output.                          โ”‚    โ”‚
โ”‚  โ”‚  The file names are passed as the complete strings.  โ”‚    โ”‚
โ”‚  โ”‚  "my file.log" stays intact.                         โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  Always use the -print0 with the xargs for the safety.       โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
find path exprThe basic syntax
-nameThe name pattern
-type f/d/lThe file, directory, symlink
-size +100MThe size greater than
-mtime -7The modified in the last 7 days
-userThe owner
-perm -4000The setuid
-exec cmd {} +The batch command
-deleteThe removal
-print0The null-separated output
-o, !, \( \)The OR, NOT, grouping

Key takeaways:

  • find searches the actual file system in real time. Unlike the locate, which searches a stale database, the find reflects the current state. The trade-off is the speed: the large trees take longer, but the results are always current .
  • The expression is a combination of the tests and the actions. The adjacent tests are the implicit AND. The -o is the OR, the ! is the NOT, and the parentheses group the subexpressions. The precedence is the NOT, the AND, then the OR .
  • The tests cover the name, the type, the size, the time, the owner, and the permissions. The -name, the -type, the -size, the -mtime, the -user, and the -perm are the most common. The -iname is the case-insensitive version, and the -newer compares against a reference file .
  • The default action is -print. The other actions are the -delete, the -exec, the -execdir, the -ok, and the -ls. The -delete is the shorthand for the removal, and it implies the -depth .
  • The -exec runs a command for each matching file. The {} is the placeholder for the file’s path, and it must be the last argument before the \; or the +. The \; runs the command per file, and the + runs it with the batch, which is much faster .
  • The -print0 and the xargs -0 handle the file names with the spaces. The -print0 separates the paths with the null characters, and the xargs -0 reads the null-separated input. The pattern is the safe way to pipe the find output to the other commands .
  • The parentheses must be escaped or quoted. The shell interprets the unquoted parentheses, and the find receives the wrong expression. The \( and the \) are the escaped forms, and the '(' and the ')' are the quoted forms .
  • The -size is rounded up to the unit. The -size 1M matches the files from 1 byte to 1 MB, which is the common source of the confusion. The -size +1M and the -size -1M are the clearer forms.

Remember: find is the most powerful file-searching tool on Linux. The syntax is find path expression, and the expression is a combination of the tests and the actions. The tests cover the name, the type, the size, the time, the owner, and the permissions. The default action is -print, and the other actions are the -delete, the -exec, and the -ls. The -exec runs a command for each file, and the + form batches the invocations. The -print0 and the xargs -0 handle the file names with the spaces. The parentheses group the conditions, and they must be escaped or quoted. The result is a tool that can find the files by any metadata and act on them, which is the foundation of the file-management skills.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!