I want to find all directories containing, for example, files named *.txt. but the output must not contain duplicates. How to do it?



find . -type f -name "*.txt" -printf '%h\n' | sort | uniq

This works as follows:

find . -type f -name "*.txt" -printf '%h\n' - find all files that end in *.txt and print it's directory (%h) followed by a newline.

| sort - sort the directories

| uniq - remove duplicates

  • Sir I can't find any article that states the use of %h with printf, please give me a link – Edward Torvalds Nov 22 '14 at 5:46
  • Dear Mr Trovalds Esq. If you type man find at the shell, then type /%h you will be taken to the description of the %h directive. If you were to scroll up a page or two from there, you will see that it's under -printf. – garethTheRed Nov 22 '14 at 7:27
  • this command gives an error on Ubuntu 14, find: paths must precede expression: <file name> Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression], but if i use doublel-quotes ("*txt" instead of *.txt) it does not. secondly, it will also list folder name abc.txt, which not as intended – Edward Torvalds Nov 23 '14 at 21:41
  • @edwardtorvalds - good spot, so it does. Thanks for the edits. – garethTheRed Nov 23 '14 at 22:06
  • oops we forget to put - before name in second line, my apologies – Edward Torvalds Nov 23 '14 at 22:08

POSIX compatible code which should work for any filename:

find . -name '*.txt' -printf '%h\0' | tr '\0\n' '\n\0' | sort -u | tr '\0\n' '\n\0'

A problem can be that directory names can contain newlines, therefore the output from find should be NUL terminated. In order to have readable output pipe the result of sort through tr:

find . -name "*.txt" -printf '%h\0' | sort -zu | tr '\0' '\n'

Any newline in a directory name can probably be determined by looking at the next line, if it starts with ./ it was not a newline in a directory.

  • 1
    “names that contain newlines” and “readable output” don’t belong in the same paragraph. A pathname of the form ./abcdef/ghi␊./Documents/foo (where is a newline) will look like ./abcdef/ghi followed by ./Documents/foo. – G-Man Nov 21 '14 at 23:36
  • your answer create produce same output as find . -name *.txt -printf '%h\n' | sort | uniq(answer above), but above one is more neat – Edward Torvalds Nov 23 '14 at 21:09

With GNU find and bash

find . -type d -exec bash -c \
$'for f; do find \"$f\" -maxdepth 1 -type f  -name \'*.txt\' -printf \'%h\\n\' -quit; done'\
_ {} +

This should work for you:

find . -iname "*.txt" -exec dirname {} \; | sort | uniq

The find + exec will get the directory names of all the *.txt files, sort|uniq will get you the unique such directories.

  • That doesn't work if there are newlines in the diretory names – Anthon Nov 21 '14 at 21:09

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.