GNU find: Search in current directory first
how can I tell find to look in the current folder first and then continue search in subfolders开发者_运维技巧? I have the following:
$ find . -iname '.note'
folder/1/.note
folder/2/.note
folder/3/.note
folder/.note
What I want is this:
$ find . -iname '.note'
folder/.note
folder/1/.note
folder/2/.note
folder/3/.note
Any ideas?
find
's algorithm is as follows:
- For each path given on the command line, let the current entry be that path, then:
- Match the current entry against the expression.
- If the current entry is a directory, then perform steps 1 and 2 for every entry in that directory, in an unspecified order.
With the -depth
primary, steps 1 and 2 are executed in the opposite order.
What you're asking find
to do is to consider files before directories in step 2. But find
has no option to do that.
In your example, all names of matching files come before names of subdirectories in the same directory, so find . -iname '.note' | sort
would work. But that obviously doesn't generalize well.
One way to process non-directories before directories is to run a find
command to iterate over directories, and a separate command (possibly find
again) to print matching files in that directory.
find -type d -exec print-matching-files-in {} \;
If you want to use a find
expression to match files, here's a general structure for the second find
command to iterate only over non-directories in the specified directory, non-recursively (GNU find required):
find -type d -exec find {} -maxdepth 1 \! -type d … \;
For example:
find -type d -exec find {} -maxdepth 1 \! -type d -iname '.note' \;
In zsh, you can write
print -l **/(#i).note(Od)
**/
recurses into subdirectories; (#i)
(a globbing flag) interprets what follows as a case-insensitive pattern, and (Od)
(a glob qualifier) orders the outcome of recursive traversals so that files in a directory are considered before subdirectories. With (Odon)
, the output is sorted lexicographically within the constraint laid out by Od
(i.e. the primary sort criterion comes first).
Workaround would be find . -iname '.note' | sort -r
:
$ find . -iname '.note' | sort -r
folder/.note
folder/3/.note
folder/2/.note
folder/1/.note
But here, the output is just sorted in reverse order and that does not change find's behaviour.
For me with GNU find on Linux I get both orderings with different test runs.
Testcase:
rm -rf /tmp/depthtest ; mkdir -p /tmp/depthtest ; cd /tmp/depthtest ; for dir in 1 2 3 . ; do mkdir -p $dir ; touch $dir/.note ; done ; find . -iname '.note'
With this test I get the poster's first result. Note the ordering of 1 2 3 .
. If I alter this ordering to to . 1 2 3
rm -rf /tmp/depthtest ; mkdir -p /tmp/depthtest ; cd /tmp/depthtest ; for dir in . 1 2 3 ; do mkdir -p $dir ; touch $dir/.note ; done ; find . -iname '.note'
I get the poster's second result.
In either case adding -depth to find does nothing.
EDIT:
I wrote a perl oneliner to look in to this further:
perl -e 'opendir(DH,".") ; print join("\n", readdir(DH)),"\n" ; closedir(DH)'
And I ran this against /tmp/depthtest after running testcase 1 with these results:
.
..
1
2
3
.note
I ran it again after testcase 2 with these results:
.
..
.note
1
2
3
Which confirms that the results are in directory order.
The -depth
option to find only controls whether e.g. ./1/.note
is processed before or after ./1/
, not whether ./.note
or ./1/
is first, so the order of the results is purely based on directory order (which is mostly creation order).
It might be helpful to look at How do I recursively list all directories at a location, breadth-first? to learn how to work around this problem.
find -s . -iname ".note"
doesn't help? or find . -iname '.note'|sort
?
Find in the current folder
find ./in_save/ -type f -maxdepth 1| more
==>73!
精彩评论