Print the directory where the 'find' linux

2020-04-20 05:35发布

问题:

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 :(

回答1:

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


回答2:

The quick and easy answer for stripping off a file name and showing only the directory it’s in is dirname:

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