Combining Find And Shell Commands With -Exec

Locating Files for Batch Operations

The find command in Linux provides a powerful way to locate files and directories based on flexible criteria. With over 50 different tests, find can match files by name, size, modification time, permissions, ownership, and many other attributes.

To use find effectively, understanding how to build complex criteria with logical operators is key. Tests can be combined to zero in on specific files for various administrative and automation tasks.

The find Command for Locating Files Based on Criteria

At its simplest, find takes a starting directory and outputs any matching files and folders under that path:

# Find all files under /var/log
find /var/log

By adding tests, the results can be narrowed down based on specific attributes:

  
# Find files over 1MB in size
find /home -size +1M

Dozens of useful tests like -name, -mtime, -type, and -user exist to matching based on file names, timestamps, types, owners, and more. Tests can be combined to select files based on multiple specific criteria.

Matching Files with Tests Like -name, -size, -mtime

The -name test matches based on file name:

  
# Find files named access.log
find /var/log -name access.log  

-size checks against the size of files:

  
# Find files over 100MB in size
find /backup -size +100M

While -mtime matches based on the last modification time in days:

# Find files modified over 180 days ago
find /var/log -mtime +180

Some other useful tests and examples include:

  • -type f

    # Find regular files

  • -perm 755

    # Match based on permissions

  • -user john

    # Match files owned by john

  • -group admins

    # Match files owned by admins group

Logical Operators to Build Complex Criteria

By combining tests with logical operators, you can craft precise criteria to pinpoint files based on multiple attributes. The main logical operators are:

  • -and

    : Match only if both conditions are met

  • -or

    : Match if either condition is met

  • -not

    : Negates or reverses the result of a test

Some examples of logical operators:

# Files over 1GB owned by john
find /home -size +1G -and -user john

# Files over 2 days old OR named tmp
find /var/tmp -mtime +2 -or -name tmp

# Files that don't start with temp  
find /var/tmp -not -name "temp*"  

Grouping long sets of tests is also possible by escaping parentheses:

# Long criteria grouped
find /var/log \( -name "*.log" -and -mtime +180 \) \  
           -or \( -size +500M -and -exec gzip {} \; \)

Performing Actions on Matching Files

Locating files with find is just half of the usefulness. The real power comes from being able to perform operations and actions on the matches.

This is accomplished with the -exec option, which runs any shell command on the results by substituting {} for the file name.

The -exec option to perform commands on results

The basic syntax for -exec is:

  
find starting_path tests -exec command_on_matches {} \;

For example, to compress *.log files over 10 days old under /var/log:

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

The {} will be replaced by the name of each matching file to compress it with gzip.

Passing {} as the matching file name

The {} syntax lets you easily operate on the files find outputs without manual intervention:

# Delete old temp files  
find /tmp -name "tmp*" -mtime +10 -exec rm {} \;

# Change permissions on media files
find /home -type f -exec chmod 644 {} \;  

It works the same for any number of matches – the command runs individually for every resulting file name.

Terminating commands properly with \;

The semicolon \; is important for terminating the -exec properly for each run:

   
# Good, will run rm properly per file
find . -type f -name "*" -exec rm {} \;

# Bad, tries to delete * literally  
find . -type f -name "*" -exec rm {}  

Without the \; files will not substitute right and operations can fail or be destructive.

Use Cases and Examples

Combining find with -exec opens many possibilities for practical use cases. Any repetitive task based on file attributes is a candidate for automation with find.

Archiving Old Log Files

Log rotation is essential for limiting disk consumption. Finding and compressing old logs is easy:

  
# Archive logs over 180 days  
find /var/log -type f -mtime +180 -exec gzip {} \;

# Delete archived logs over 1 year old
find /var/log -name "*.gz" -mtime +365 -exec rm {} \;

Finding and Deleting Temporary Files

Clearing out old temporary files helps reclaim wasted disk space:

# Remove files not modified in over 90 days
find /tmp -type f -mtime +90 -exec rm {} \;

Changing Permissions on Directories

Updating permissions recursively is simple with find:

# Add group write to trees
find /home -type d -exec chmod g+w {} \;

# Remove world write 
find /home -type d -exec chmod o-w {} \;

Other Common Automation Tasks

Many other administrative tasks are also good candidates for find automation:

  • Searching logs for failures or errors
  • Updating access times on inactive files
  • Moving old files to other partitions
  • Removing outdated backups

Anything needing recursive scaling across files can benefit from find with -exec.

Improving Efficiency and Readability

When chaining together many find commands with -exec, there are some best practices to make things cleaner and more efficient.

Grouping Long Lists of Criteria

Finding files often requires long lists of criteria. Grouping them with escaping makes things readable:

find /var/log \( -name "*.log" -and -mtime +180 \) \  
           -or \( -size +500M -and -exec gzip {} \; \)

Splitting Long -exec Lines

Similarly, splitting -exec across lines keeps things clean:

  
find /home -type f -mtime +180 
           -exec gzip {} \;  
           -exec mv {} /archive \;

Proper Quoting and Escapes

When executing commands, proper escaping and quoting ensures operate as intended:

find . -type f -exec sh -c 'rm "{}" ;' \;

This quotes the {} to allow for filenames with spaces.

Putting It in a Script

For reusable batch operations, put commands in a script:

  
#!/bin/bash

# Find files  
find "/home" -name "*.tmp" -mtime +30  

# Take action   
-exec rm {} \;  

This way you can repeatedly automate tasks consistently.

Leave a Reply

Your email address will not be published. Required fields are marked *