breadth-first option in the Linux `find' utility?

Is there any breadth-first/depth-first option in the Linux `find' utility?


There's nothing built-in to find, even GNU find. You can postprocess the output of find to sort by number of slashes, for example with Perl:

find ... | perl -e 'print sort {$a=~s!/!/! <=> $b=~s!/!/!} <>'
  • <> is the list of all input lines;
  • $a =~ s!/!/!g is the number of slashes in $a, which we use as the sort criterion.

If you can use zsh:

echo **/*(oe\''REPLY=${REPLY//[^\/]}'\')
  • **/* lists all files in the current directory and subdirectories.
  • The stuff inside the parentheses is a glob qualifier.
  • The glob qualifier oe controls the order in which matches are returned: they are sorted by the value of REPLY after running the code here in quotes for each match with REPLY initially set to the matched path.
  • Said code transforms $REPLY to delete everything except slashes. So the result consists of everything at depth 1 (empty resulting $REPLY), then everything at depth 2 ($REPLY ends up to be /), depth 3 (//), etc.

Nope

Go to this question on SO for workarounds.


My feeling is that you can. It involves grep and such and a loop, but I find it works very well, specifically for your case about the find not needing to be completed.

It is more resource intensive because of:

  • Lots of forking
  • Lots of finds
  • Each directory before the current depth is hit by find as many times as there is total depth to the file structure (this shouldn't be a problem if you have practically any amount of ram...)

This is good because:

  • It uses bash and basic gnu tools
  • It can be broken whenever you want (like you see what you were looking for fly by)
  • It works per line and not per find, so subsequent commands don't have to wait for a find and a sort
  • It works based on the actual file system separation, so if you have a directory with a slash in it, it won't be listed deeper than it is; if you have a different path separator configured, you still are fine.
#!/bin/bash 
depth=0

while find -mindepth $depth -maxdepth $depth | grep '.'
do
    depth=$((depth + 1))
done

You can also fit it onto one line fairly(?) easily:

depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done

But I prefer small scripts over typing...