7

Let's say I'm in a directory which has some subdirectories, dir1, dir2, and dir3. Each of these directories have a file foo and I would like to execute the same command on each foo in each of the directories and have that command executed from inside that directory.

If I were to do it "by hand", it would look something like this:

cd dir1
(execute on foo)
cd ../dir2
(execute on foo)
cd ../dir3
(execute on foo)

It is imperative that the command be executed from each of the directories. foo is a batch scheduling script (for HTCondor, if you care to know) and must be executed from each subdirectory so that the output of the runs started by the scheduling scripts will end up in each subdirectory.

The question "Find a file and execute a command in the file's directory", as far as I can tell, does not answer my question. The first answer to that question is more of a workaround which will not work in my case, and the second answer does not have enough of an explanation for me to know how to use it.

  • @roaima, please explain how it is a duplicate. The first answer of that question does not help me, it's more of a work around, and the second answer does not make any sense to me. It needs more explanation for me to know how to use it. – NeutronStar Jul 14 '16 at 20:41
17

Assuming your find supports it, use the -execdir option instead of -exec

find * -name 'foo' -execdir pwd \;

If it doesn't, please provide details of your platform and/or distribution (as appropriate).

  • When you start hitting "find: The relative path ‘./node_modules/.bin’ is included in the PATH environment variable,": askubuntu.com/questions/621132/… – Ciro Santilli 新疆改造中心996ICU六四事件 Apr 9 at 9:08
  • Sorry if I may write it like that, but -execdir (on Ubuntu) is shit, because it doesn't give you {}, but the parent of {}. – uav May 13 at 16:00
  • @uav without knowing your use case I can't help you. But in response to your whinge the documentation clearly states "Like -exec, but the specified command is run from the subdirectory containing the matched file". – roaima May 13 at 16:59
  • Yes, right, it's a special case if you're looking for -type d (= directory) and then it's sub-optimal. – uav May 13 at 17:05
  • Without knowing your use case i can't help you. – roaima May 13 at 17:20
1

Assuming you know exactly what directories to run your command in,

for dir in dir1 dir2 dir3; do
    ( cd "$dir" && somecommand foo )
done

or, looping over the foo files,

for foo in */foo; do
  ( cd "${foo%/*}" && somecommand foo )
done

The subshell prevents the cd to affect the working directory of the rest of the script. The ${foo%/*} parameter substitution expands to the name of the directory where the foo file lives (by removing everything after the last / in the value of $foo).

Using standard find to do the same thing (in the case where the foo files may live deep down in a directory structure):

find . -type f -name foo -exec sh -c '
    for foo do
        ( cd "${foo%/*}" && somecommand foo )
    done' sh {} +

In words: Find all regular files called "foo" anywhere in the current directory or below and give their pathnames to this shell script in batches. The shell script shall iterate over the given pathnames, change directory to the directory portion of each pathname and if that succeeds, execute somecommand foo.

For a solution that uses the nonstandard -execdir, see roaima's answer. His answer adapted to my example:

find . -type f -name foo -execdir somecommand foo ';'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.