While researching for this question: Find and move directories based on file type and date, I stumbled upon a problem of my own.
First I created a bunch of directories with files in them:
seq 10 | while read dir; do
mkdir dir$dir
touch dir$dir/file.txt
seq 5 | while read file; do
touch dir$dir/file${dir}_$file
done
done
Then I tried following find command:
$ find -type f -name "*.txt"
./dir6/file.txt
./dir8/file.txt
./dir10/file.txt
...
Works as expected.
Now with an -exec
:
$ find -type f -name "*.txt" -exec sh -c 'echo mv -v "${0%/*}" ../bar' {} \;
mv -v ./dir6 ../bar
mv -v ./dir8 ../bar
mv -v ./dir10 ../bar
...
Works as expected.
Now the actual command:
$ find -type f -name "*.txt" -exec sh -c 'mv -v "${0%/*}" ../bar' {} \;
`./dir6' -> `../bar/dir6'
It stops after the first mv
. No error message. Exit status is 0. The directory bar
exists and dir6
is moved correctly.
When I execute again this happens:
$ find -type f -name "*.txt" -exec sh -c 'mv -v "${0%/*}" ../bar' {} \;
`./dir8' -> `../bar/dir8'
Again stop after the first mv
. Exit status is 0. dir8
is moved correctly.
Why does find
stop after the first mv
? Because the directory is moved and find
is confused? Why does it not print an error or return an error exit status?
When I create more directories and more files it has the same behaviour.
In the question linked above the problem is that find
executes once without problem but print errors for all matches after that. Is this related?
Using find (GNU findutils) 4.4.2
.
Best Answer
In:
find
opens the current directory (.
), gets the content (list1
). Then goes on to process that list. It processesdir6
; as that file is a directory, it chdirs into it, opens it gets a second list of files (list2
), processesfile.txt
and does:Now,
find
's current directory has not changed, but its path has changed: it is now../bar/dir6
. After finishing traversing the content ofdir6
, it goes back up (chdir("..")
) and is now in../bar
.find
detects that the directory is not the same as before and exits.