Jodo
Jodo

Reputation: 4763

Bash - dirname not working with substitution

When using find with $(dirname {}), it always just outputs "." as the dirname. E.g. for:

find . -name \*.h -exec echo {} \; -exec echo $(dirname {}) \;

outputs:

./folder/folder.h
.
./folder/sub_folder/sub_folder.h
.
./test.h
.

But I would expect this:

./folder/folder.h
./folder
./folder/sub_folder/sub_folder.h
./folder/sub_folder
./test.h
.

Interestingly, creating a new shell for each find generates the correct output:

find . -name \*.h -exec sh -c 'echo $0; echo $(dirname $0);' {} \;

Upvotes: 0

Views: 691

Answers (3)

kvantour
kvantour

Reputation: 26481

You might actually want to use this:

find . -name '*.h' -type f -printf "%p\n%h\n"

When you look at man find under the printf format section, you will notice that there are a plethora of useful flags.

Upvotes: 0

sungtm
sungtm

Reputation: 577

After having tested the above command through a script, it has been observed that $(dirname {}) is expanded to current directory .'.

mkdir -p test1/test2
touch test1/test2/tests.h
find . -name \*.h -exec echo {} \; -exec echo $(dirname {}) \;
./test1/test2/tests.h
.

echo "find . -name \*.h -exec echo {} \; -exec echo $(dirname {}) \;" > checkh.sh

bash -vx checkh.sh

find . -name \*.h -exec echo {} \; -exec echo . \;
+ find . -name '*.h' -exec echo '{}' ';' -exec echo . ';'
./test1/test2/tests.h
.
.

That's why the output is always displayed as only . current directory.

So, use your mini-script sh -c style or Kent's solution.

A slight modification from your command will also work, i.e., put echo inside command substitution:

find . -name \*.h -exec echo {} \; -exec $(echo dirname {}) \;
./test1/test2/tests.h
./test1/test2

Test case on the modification is as follows:

echo "find . -name \*.h -exec echo {} \; -exec $(echo dirname {}) \;" > checkh2.sh 
bash -vx checkh2.sh 
find . -name \*.h -exec echo {} \; -exec dirname {} \;
+ find . -name '*.h' -exec echo '{}' ';' -exec dirname '{}' ';'
./test1/test2/tests.h
./test1/test2

Upvotes: 2

Kent
Kent

Reputation: 195049

This line gives what you want:

find . -name *.h -print -exec dirname {} \;

Upvotes: 0

Related Questions