End up with 4 invocations instead of 3 when using this find -execdir {} + (plus)

find

I read here that you can count the number of invocations of command in -exec command {} + by piping | wc -l to the end of it.

While I understand that -execdir is different, in that, for every matching sub-directory that find discovers, it runs an invocation of the command from the sub-directory it's contained in, if I have more than one file that matches in a sub-directory, shouldn't I end up with the number of invocations equal to the number of matching sub-directories, and not the number of invocations matching the number of matching files in those sub-directories?

I am ending up with the latter when I run the following:

$ find . -name "bob*" -execdir echo {} + | wc -l

The man page for the execdir command {} + states that the former should be the case:

As with the -exec action, the + form of the -execdir will build
a command line to process more than one matched file, but any given
invocation of command will only list files that exist in the same
sub-directory.


i.e.

I'm getting:

./file1inDir1
./file2inDir1
./file3InDir2
./file4InDir3

When I'm expecting this, based on the man page:

./file1inDir1 ./file2inDir1
./file3InDir2
./file4InDir3

Best Answer

This is a performance issue of find. In findutils version 4.3.4, a workaround had to restrict the number of arguments that -execdir ... {} + will use to 1. In version 4.5.9 the limit was removed.

See an example:

$ mkdir -p dir{1..3}
$ touch dir{1..3}/file1 dir2/file{1..3}
$ find
.
./dir1
./dir1/file1
./dir2
./dir2/file1
./dir2/file2
./dir2/file3
./dir3
./dir3/file1

With -execdir {} +, the command should be executed 3 times. The second invocation should have 3 arguments.

With find 4.4.2:

$ find-4.4.2 . -name "file*" -execdir sh -c 'echo "Executing $@ in $(pwd)"' find-sh {} +
Executing ./file1 in /path/to/dir1
Executing ./file1 in /path/to/dir2
Executing ./file2 in /path/to/dir2
Executing ./file3 in /path/to/dir2
Executing ./file1 in /path/to/dir3

With find 4.6.0:

$ find-4.6.0 . -name "file*" -execdir sh -c 'echo "Executing $@ in $(pwd)"' find-sh {} +
Executing ./file1 in /path/to/dir1
Executing ./file1 ./file2 ./file3 in /path/to/dir2
Executing ./file1 in /path/to/dir3