Disco Disco - 5 months ago 8
Linux Question

Print the directory where the 'find' linux command finds a match

I have a bunch of directories; some of them contain a '.todo' file.

/storage/BCC9F9D00663A8043F8D73369E920632/.todo
/storage/BAE9BBF30CCEF5210534E875FC80D37E/.todo
/storage/CBB46FF977EE166815A042F3DEEFB865/.todo
/storage/8ABCBF3194F5D7E97E83C4FD042AB8E7/.todo
/storage/9DB9411F403BD282B097CBF06A9687F5/.todo
/storage/99A9BA69543CD48BA4BD59594169BBAC/.todo
/storage/0B6FB65D4E46CBD8A9B1E704CFACC42E/.todo


I'd like the 'find' command to print me only the directory, like this

/storage/BCC9F9D00663A8043F8D73369E920632
/storage/BAE9BBF30CCEF5210534E875FC80D37E
/storage/CBB46FF977EE166815A042F3DEEFB865
...


here's what I have so far, but it lists the '.todo' file as well

#!/bin/bash
STORAGEFOLDER='/storage'
find $STORAGEFOLDER -name .todo -exec ls -l {} \;


Should be dumb stupid, but i'm giving up :(

Answer

To print the directory name only, use -printf '%h\n'. Also recommended to quote your variable with doublequotes.

find "$STORAGEFOLDER" -name .todo -printf '%h\n'

If you want to process the output:

find "$STORAGEFOLDER" -name .todo -printf '%h\n' | xargs ls -l

Or use a loop with process substitution to make use of a variable:

while read -r DIR; do
    ls -l "$DIR"
done < <(exec find "$STORAGEFOLDER" -name .todo -printf '%h\n')

The loop would actually process one directory at a time whereas in xargs the directories are passed ls -l in one shot.

To make it sure that you only process one directory at a time, add uniq:

find "$STORAGEFOLDER" -name .todo -printf '%h\n' | uniq | xargs ls -l

Or

while read -r DIR; do
    ls -l "$DIR"
done < <(exec find "$STORAGEFOLDER" -name .todo -printf '%h\n' | uniq)

If you don't have bash and that you don't mind about preserving changes to variables outside the loop you can just use a pipe:

find "$STORAGEFOLDER" -name .todo -printf '%h\n' | uniq | while read -r DIR; do
    ls -l "$DIR"
done
Comments