I want to print the names of all subdirectories that contain zero files (they may contain subdirectories). The following works for the current directory:

$ ls -p | grep -v / | wc -l | \
  xargs -I % test % -eq 0 && pwd

I think that there might be a more elegant solution, any suggestions? And how do I have to change it to recurse through all subdirectories?

I have a test structure: test/test1/test4 and test/test2/test3/test5. The only file is in test/test1. I want to run the command in the basis directory (test/). The results are supposed to be: test/ ; test/test2/ ; test/test2/test3/ because those are the directories that only contain subdirectories but no files. Additional accceptable would be the empty endpoints test/test1/test4/ and test/test2/test3/test5.

  • find . -type d -empty should do that. – Jos Mar 23 '20 at 10:23
  • @jos no, it only lists empty directories but it doesn't include any directories that include only subdirectories but no files. Those are exactly those I am looking for. – jamacoe Mar 23 '20 at 10:34
  • it should not traverse the directory structure? its only 2 directory deep? – bac0n Mar 23 '20 at 10:51
  • @bac0n it should, that is the question – jamacoe Mar 23 '20 at 10:55

Using fgrep to filter out directories with files:

$ find -type d | \
  grep -xFv -f <(find -type f -printf %h\\n)

  • @jamacoe please edit this information into your question – steeldriver Mar 23 '20 at 13:23
  • This works now, nice idea! – jamacoe Mar 23 '20 at 13:52
  • @bac0n Many file and directory names contain special characters (a music library) so I received the error message "xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option". Adding -0 to xargs and -print0 to the latter find solved it, so now the correct answer is: find -type d | grep -xFv -f <(find -type f -print0 | xargs -0 -n 1 dirname) – jamacoe Mar 23 '20 at 14:17
  • I remove xargs alltogether and used printf instead – bac0n Mar 23 '20 at 14:26
  • This is a pretty neat idea and works great as long as you have no newlines in your file names ;-) Not very common, but used in a script it might introduce vulnerabilities. Using it in a script needs some comment or you won't know what this does some thime later ;-) – pLumo Mar 23 '20 at 16:48

Something like this:

find . -type d -exec bash -c 'files=$(find $1 -mindepth 1 -maxdepth 1 -type f | wc -l) ; [[ $files -ne 0 ]] && exit 1 ; exit 0' script {} \; -print

The bash -c ... is just a "small" script that returns 0 or 1 after checking for files in the directory.

  • This is the first working solution and it shows the right output :) But imho to include a script lacks elegance. Perhaps it is possible with some kind of recurse switch. – jamacoe Mar 23 '20 at 13:50

A different approach to the problem:

# Enable advanced glob
shopt -s globstar
# Enable matching hidden files (.*)
shopt -s dotglob
for d in **/; do
   for f in "$d"/*; do
     [ -f "$f" ] && nofiles=false && break
   [ $nofiles = true ] && echo "$d"
shopt -u globstar
shopt -u dotglob

Loop through all folders, inside them loop all items and check for files.

Not the shortest script, but will not fail on newlines, spaces or alike in your file names. And it is easy to read also when you look at it again after 5 years ;-)

  • looping through directories was my first idea given the approach in my question. And true, much easier to read. Personally, I prefer one liners like bac0n's and I am going to comment it thoroughly :) – jamacoe Mar 23 '20 at 21:53

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.