Difference between ‘find -exec’ and ‘find -execdir’ by example

find -exec is a commonly used command. However, some people might not be awared of the command find -execdir and their differences. In this article, we will explain the 2 differences between them.

1. ‘find -exec’ and ‘find -execdir’ execute commands in different directories

find -exec executes the commands in the starting directory, whereas find -execdir executes the commands in the directories containing the matched target.

CommandExecute commands in
find -execthe starting directory
find -execdirthe directories containing the matched target

Let’s demonstrate the above idea with an example:

  1. Create the following structure.
    noob@learnfromnoobs:~$ tree find-test/
    find-test/
    ├── dir1
    │   └── myfile1
    └── dir2
    z   └── myfile2  
    
    2 directories, 2 files
    

    You can use these commands to create the structure above.

    $ mkdir find-test
    $ mkdir find-test/dir1
    $ mkdir find-test/dir2
    $ touch find-test/dir1/myfile1
    $ touch find-test/dir2/myfile2
    
  2. Run find -exec under find-test.
    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec ls -l \;
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    

    The find command found the the files ‘myfile1’ and ‘myfile2’. As there were 2 matches, the ls command was executed twice in the starting directory (find-test) twice. That’s why we are seeing the ls result under find-test twice.

  3. Run find -execdir under find-test.

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir ls -l \;
    total 0
    -rw-rw-r-- 1 noob noob 0 Jan 27 09:55 myfile1
    total 0
    -rw-rw-r-- 1 noob noob 0 Jan 27 09:55 myfile2
    

    We get this result because we are executing ls in the directories containing the matched target (dir1 and dir2). We are seeing the ls result under dir1 and dir.

    For more information, please refer to the man page of find.

  4. If you are still not convinced with the above results, you can always use echo to check what the matched target really is.

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec echo {} \;
    ./dir1/myfile1
    ./dir2/myfile2
    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir echo {} \;
    ./myfile1
    ./myfile2
    

    As we can see, the current directory for the find -exec command is ~/find-test. For the find -execdir command, the current directories are ~/find-test/dir1 and ~/find-test/dir2, which are the directories containing the targets myfile1 and myfile2.

Important

Before executing the command, it is always good to use -ls to visually inspect the actual files that you are really working on. You never want to remove any files by accident.

noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -ls;
   524517      0 -rw-rw-r--   1 noob     noob            0 Jan 27 09:55 ./dir1/myfile1
   524518      0 -rw-rw-r--   1 noob     noob            0 Jan 27 09:55 ./dir2/myfile2

2. ‘find -execdir’ does not allow ‘.’ in $PATH environment variable

According to the find command man page,

If you use this option, you must ensure that your $PATH environment variable does not reference `.’; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you will run -execdir.

When using find -execdir, it is not allowed to have a ‘.’ in $PATH environment variable. (Some people like to put a ‘.’ in $PATH so that they don’t have to type ‘./’ when executing their programs in the current directory. This is highly not recommended. See this article if you want to know more.)

Just for experimental purposes, we can test how find -execdir would respond if there is a ‘.’ in our $PATH environment variable.

  1. Add a dot to our $PATH environment variable.
    noob@learnfromnoobs:~/find-test$ export PATH=$PATH:.
    noob@learnfromnoobs:~/find-test$ echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:.
    
  2. Let’s see if find -exec would complain or not.
    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -exec ls -l \;
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    total 8
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir1
    drwxrwxr-x 2 noob noob 4096 Jan 27 09:55 dir2
    

    The command was executed without a problem. find -exec allows us to have a ‘.’ in $PATH.

  3. Let’s see if find -execdir would complain or not.

    noob@learnfromnoobs:~/find-test$ find . -name 'myfile*' -execdir ls -l \;
    find: The current directory is included in the PATH environment variable, which is insecure in combination with the -execdir action of find.  Please remove the current directory from your $PATH (that is, remove ".", doubled colons, or leading or trailing colons)
    

    Oops! Obviously, find -execdir really doesn’t like having a ‘.’ in $PATH. The command was not allowed to be executed.


Conclusion

In summary, there are 2 difference between find -exec and find -execdir:

  1. find -exec executes the commands in the starting directory, whereas find -execdir executes the commands in the directories containing the matched target.
  2. find -execdir does not allow ‘.’ in $PATH environment variable

I hope you enjoyed this article and learned something new.

Keep learning and have fun!

Leave a Reply

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