Is there any breadth-first/depth-first option in the Linux `find' utility?
4 Answers
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 ofREPLY
after running the code here in quotes for each match withREPLY
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.
-
1The sort post process is very interesting, however, sort needs the find to be completed, and you won't have chance to control break.– LenikCommented Oct 1, 2010 at 7:49
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...
From https://stackoverflow.com/a/23948137/1865272
#!/bin/bash
queue="$1"
shift
while [ -n "$queue" ]
do
echo "$queue" | xargs -I'{}' find {} -mindepth 1 -maxdepth 1 $*
queue=`echo "$queue" | xargs -I'{}' find {} -mindepth 1 -maxdepth 1 -type d`
done
From Jethro Yu https://stackoverflow.com/users/542730/jethro-yu