3

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?

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
dmorlock
  • 1,993
  • 4
  • 18
  • 22
  • 1
    Funny. GNU find on Linux gives me your first output, GNU find on Cygwin gives me your second. No idea on how to influence this; `-depth` should work but doesn't. – DevSolar Nov 18 '10 at 13:10
  • Same behavior here. `-depth` seems to have no effect. – Fred Foo Nov 18 '10 at 13:14
  • 1
    @DevSolar, @larsmans: With this input, `-depth` happens to produce exactly the same result. `-depth` has no influence on whether files are processed before or after directories, it determines whether directories are processed before or after their contents. – Gilles 'SO- stop being evil' Nov 18 '10 at 21:34

5 Answers5

3

find's algorithm is as follows:

  • For each path given on the command line, let the current entry be that path, then:
    1. Match the current entry against the expression.
    2. 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).

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
1

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.

dmorlock
  • 1,993
  • 4
  • 18
  • 22
  • In ASCII ordering, `.` comes before `1`, so your output is dependent on having a particular collating locale (`$LC_COLLATE`). Most collating locales in fact do have such an ordering, but not the basic locale (`C` or synonymously `POSIX`). This locale is often used in scripts to avoid with some applications that can't cope with an ordering that is incompatible with ASCII. – Gilles 'SO- stop being evil' Nov 18 '10 at 21:32
1

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.

Community
  • 1
  • 1
sorpigal
  • 25,504
  • 8
  • 57
  • 75
0

Find in the current folder

 find ./in_save/ -type f -maxdepth 1| more

==>73!

Mikro Koder
  • 1,056
  • 10
  • 13
0

find -s . -iname ".note" doesn't help? or find . -iname '.note'|sort ?

khachik
  • 28,112
  • 9
  • 59
  • 94