When And How To Use -Execdir With Find

What is -execdir and When To Use It

-execdir is an option in the Find command on Linux and UNIX-like systems that allows executing a command or script in the original directory where each found file resides, rather than changing to the current directory of Find itself. This can avoid certain issues related to path resolution and permissions when running commands recursively on multiple directories.

-execdir differs from the more commonly used -exec option because -exec always executes the given command or script from the current working directory of Find itself. So if Find has descended into some deeply nested set of directories to find files, -exec will run the given command from that nested working directory. -execdir instead stays in the original directory local to each found file.

Situations where -execdir has advantages over -exec include:

  • Scripts or commands that rely on operating relative to the same directory as the target files and folders. -execdir ensures consistency here, whereas -exec could break such assumptions.
  • Commands that create new files or folders, where you want the output organized relative to source directory locations. -execdir respects original tree structure.
  • Copying, moving, or otherwise manipulating files where path references and permissions may break if executed from Find’s nested working directories.
  • Scripts that output processed results in their source directories or a consistent output structure. -execdir enables this organization.

In summary, the key cases for using -execdir are when the executed commands rely on operating relative to the directory local to each found file or folder. This avoids path confusion and unintended effects from Find descending recursively into arbitrary directory trees.

Running Commands Safely in Original Directories

One of the main benefits of -execdir is avoiding issues caused by commands changing into different working directories than where the target files reside. This can introduce problems with both path resolution and permissions.

For example, consider a Find command that matches files across multiple directories on a system, including directories that the user might not normally have access to. The Find process can access these files because it runs as the root user. However, if -exec is used to then call a command on the matched files, and that command gets executed from Find’s internal working directory, the command may fail for lack of permissions on that nested directory path!

Using -execdir avoids this by staying within the original directory that the target files were found in. Since Find had access, that means the executed command retains access as well in each directory context, preventing permission errors.

Similarly, -execdir avoids path confusion issues caused by Find changing directories internally. Any relative paths used by commands stay valid when running in the same directories as the target files. Absolute paths also work consistently regardless of Find’s internal path state, since the command executes locally on each found file or directory tree.

In summary, -execdir provides safety by executing commands in the original directories local to the found files themselves. This prevents unintended behavior caused by Find descending into arbitrary nested directory structures behind the scenes.

Syntax and Examples

The basic syntax of -execdir used with the Find command is:

find [starting-directory] [criteria] -execdir command {} +

Where:

  • [starting-directory]

    is the top-level directory where Find begins recursive searching.

  • [criteria]

    are the search criteria that match target files or folders, such as file name patterns, modification times, sizes, ownership, permissions etc.

  • command

    is the command to be executed, which can be an executable, script, or any shell command.

  • {}

    are placeholders for each found file/folder path to be substituted into the command.

  • +

    terminates command execution, running it asynchronously on batches of found files for performance.

Some examples demonstrating common usage patterns:

# Run file compression utility recursively
find /var/logs -type f -execdir gzip {} +

# Recursively set permissions 
find /home/*/public_html -type d -execdir chmod 755 {} +  

# Run custom Python script on found files
find . -type f -name '*.txt' -execdir python process.py {} +

Breaking down one of these commands:

find /var/logs -type f -execdir gzip {} +

This finds all normal files (-type f) recursively within /var/logs, then runs the gzip utility to compress each matched file in place, using -execdir to stay in the original directories to avoid any issues gzip might have with path resolution or permissions when changing directories.

The {} placeholders are substituted with the full path of each found log file, so gzip can operate on the exact matched paths while -execdir iterates through efficiently.

Advanced Usage Tips

While the basic -execdir syntax works well for simple cases, more advanced usage can optimize performance, safely chain together commands, and better handle errors.

Performance Considerations

-execdir has a performance advantage over -exec when running commands that do significant file operations or processing. By staying in the original directories, -execdir avoids the accumulated overhead of Find having to internally descend and ascend entire directory trees over and over.

However on very large finds, -execdir may accumulate too many argument lists which can stretch system memory limits. The {} + syntax runs commands asynchronously in batches, but for extreme cases, piping finds into xargs can address this.

Also when doing parallel computing, distributing finds across workers will be higher performance than relying on -execdir’s command batching. But -execdir is ideal for simple parallelization of common system administration commands.

Chaining Multiple Commands

It is possible to safely chain different -execdir commands together by wrapping them in brace expansion syntax:

find . -type d -execdir \
  { chmod 755 {} ; touch {}/.updated } +

This will recursively set 755 permissions on directories, then touch a .updated file in each folder after being ensured the folder is accessible. This shows how series of operations can leverage -execdir to account for potential issues like permissions when changing context.

Handling Errors and Exit Statuses

Unlike -exec which halts Find execution if any command fails, -execdir will keep iterating on errors by default. To detect errors from the executed commands, check the exit status of Find itself, or chain commands with && and || bash operators:

  
find /home -type f -execdir rm {} \; -print -execdir grep -L {} /dev/null \;

Here any missing files will be detected after attempted removal, while Find keeps going. More complex logic around command exits can be built using && and || inside brace expansion.

Common Gotchas To Avoid

While -execdir solves various path and permission issues, there are still some pitfalls to avoid with its usage compared to regular -exec:

Relative vs Absolute Paths

-execdir relies on executing commands from original directories, so any relative paths used in commands must be carefully structured. Paths relative to $PWD work reliably, but refs like ../parentdir may break in some directory contexts.

Using absolute paths in commands avoids this, but loses some portability. Know the command being run and whether paths are built appropriately for -execdir’s behavior.

Permission Errors

Although -execdir prevents permission issues caused by Find itself changing directories, the executed commands can still fail permissions in the target directories. If errors happen, adjust Find search criteria or command flags to restrict operations to permitted paths.

For example finding world-writable files then attempting chmod commands could fail without recursively checking writeability first in criteria.

Data Loss Concerns

Accidentally running destructive commands like rm without proper Find restrictions can wreak havoc. Make sure criteria are specific enough before doing dangerous batch operations. Piping finds into xargs first can also help preview target paths.

Also be cautious replacing {} placeholders in commands with unquoted wildcard patterns, which could mass expand and delete unintended files.

Leave a Reply

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