4

I want to find all directories that are named Contents and then from the list of found results, I want to filter them and only include those that have a file named Database.json directly inside them.

find / -type d -name Contents 2>/dev/null |
while read dir;
do
    if [ -f $dir/Database.json ]; then
        echo $dir
    fi
done

This code works. But I think it's overkill. I think there should be an easier way to do it.

Can I rewrite this code to become simpler?

1
  • 1
    have you try something like: ls **/Contents/Database.json? Jul 5 at 5:34

1 Answer 1

6

With GNU find, you can do:

LC_ALL=C find . -path '*/Contents/Database.json' -printf '%h\n'

Where %h gives you the head of the path, that is the dirname.

LC_ALL=C is needed for * to match any sequence of bytes regardless of what the user's locale regards as characters, as file paths can be made of any sequence of bytes other than 0 which don't have to make up characters in the user's locale.

Similar with zsh, also giving you a sorted list, excluding hidden ones, add also reporting symlinks to directories that contain a Database.json:

print -rC1 -- **/Contents/Database.json(N:h)

For a closer equivalent to GNU find's approach:

print -rC1 -- **/Contents(NDoN/e['
  [[ -e $REPLY/Database.json || -L $REPLY/Database.json ]]'])

Where:

  • D includes hidden files (Dot files)
  • oN does Not order the list.
  • / selects the files of type directory.
  • e['code'] checks that the dirs contain a Database.json file of any type including broken symLink.

In any case, you cannot post-process the list like you do there. Instead, you'd do:

With GNU find and zsh or bash:

while IFS= read -ru3 -d '' file; do
  something with "$file"
done 3< <(LC_ALL=C find . -path '*/Contents/Database.json' -printf '%h\0')

With zsh:

for file (**/Contents/Database.json(N:h)) something with $file

See also:

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.