Execute a command where a file is found

If you run this command your touch file will be run, potentially multiple times, from the directory in which the command has been started:

find -name '*.pdf' -exec touch file \;

On the other hand, if you run this variant, each instance of the command will be run in the target file's directory:

find -name '*.pdf' -execdir touch file \;

In both cases you can see this in action by substituting the touch file with either echo {} and/or pwd.


From manpage:

-execdir command ;
-execdir command {} +

    Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find.


You can extract the filename's directory with dirname and take it from there, something like this:

find . -name "*.pdf" -type f -exec bash myscript {} \;

where the file myscript contains the following:

dir=$(dirname "$1")
cd "$dir"
touch file

With zsh you could use glob qualifiers to select e.g. only .pdf files and via modifiers save the directory names in an array with unique elements and then cd into each of those directories and run your command. This way you are running your command only once in each directory, irrespective of the number of .pdfs that were found in that directory:

dirlist=(**/*.pdf(.:a:h))
for d in ${(u)dirlist[@]}
  (cd $d && touch file)

or

typeset -U dirlist
dirlist=(**/*.pdf(.:a:h))
for d in ${dirlist}
  (cd $d && touch file)

You can further combine modifiers and qualifiers, e.g. to glob for regular files (hidden and non-hidden) with the extension .bkp and save unique directory names in an array:

dirlist=(**/*.bkp(D.:a:h))

Tags:

Path

Command

Find