0

In my project various jobs are created as files in directories inside subdirectories. But usually the case is I find that the jobs are mostly in some dirs and not in the most others

currently I use

find $DIR -type f | head -n 1 

to know if the directory has atleast 1 file , but this is a waste

how to efficiently find if a linux directory including sudirectories has at least 1 file

Ram
  • 1,155
  • 13
  • 34
  • Does this answer your question? [Checking from shell script if a directory contains files](https://stackoverflow.com/questions/91368/checking-from-shell-script-if-a-directory-contains-files) – Paul R Feb 16 '20 at 08:51
  • Another twist `[ "$(find . -type f -printf "." | grep -c '.')" -eq 1 ]` which tries to be efficient by only outputting a single `'.'` per file. For a count of the files `find . -type f -printf "." | wc -c` – David C. Rankin Feb 16 '20 at 11:01

3 Answers3

1

Your code is already efficient, but perhaps the reason is not obvious. When you pipe the output of find to head -n 1 you probably assume that find lists all the files and then head discards everything after the first one. But that's not quite what head does.

When find lists the first file, head will print it, but when find lists the second file, head will terminate itself, which sends SIGPIPE to find because the pipe between them is closed. Then find will stop running, because the default signal handler for SIGPIPE terminates the program which receives it.

So the cost of your pipelined commands is only the cost of finding two files, not the cost of finding all files. For most obvious use cases this should be good enough.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
0

Try this

find -type f -printf '%h\n' | uniq

The find part finds all files, but prints only the directory. The uniq part eliminates duplicates.

Pitfall: It doesn't work (like your example) for files containing a NEWLINE in the directory path.

Wiimm
  • 2,971
  • 1
  • 15
  • 25
0

This command finds the first subdiretory containing at least one file and then stop:

find . -mindepth 1 -type d -exec bash -c 'c=$(find {} -maxdepth 1 -type f -print -quit);test "x$c" != x' \; -print -quit

The first find iterates through all subdirectories and second find finds the first file and then stop.

Philippe
  • 20,025
  • 2
  • 23
  • 32