7

I have a find command as below that lists the matching files:

$ find . -type f -name "*.txt"

./level2/file2.txt
./level2/level3/file3.txt
./level2/level3/level4/file4.txt
./level2/level3/level4/level5/file5.txt
./output.txt

Now I'm trying to copy each of the listed files to a specific folder by chaining with exec:

$ ls copy_here | wc -l
0

$ find . -type f -name "*.txt" -exec cp {} ./copy_here \;
cp: ./copy_here/file2.txt and ./copy_here/file2.txt are identical (not copied).
cp: ./copy_here/file3.txt and ./copy_here/file3.txt are identical (not copied).
cp: ./copy_here/file4.txt and ./copy_here/file4.txt are identical (not copied).
cp: ./copy_here/file5.txt and ./copy_here/file5.txt are identical (not copied).

Can anyone help breaking down the sequence of execution to help understand the flow of execution better?

2
  • 1
    Replace cp with echo for debugging...
    – FedKad
    Commented Jul 31, 2022 at 7:35
  • 5
    @FedKad, that won't work in this case. The issue is that the cp action copies the .txt files to ./copy_here which is empty from the start and then tries to copy these files again when it gets to the ./copy_here dir. Without the copy, the error won't occur and echo won't make you any wiser. Also, OP has effectively already done this as -print is assumed if no expression is provided.
    – frippe
    Commented Jul 31, 2022 at 8:46

1 Answer 1

15

This is because of the order find is doing things. What's happening in your case is that find searches your levelX directories first, finding the .txt files and copying them to ./copy_here. (Btw, you should not rely on in which order find discovers things, so this sort of error may or may not occur. See this.)

The problem is when find then gets to copy_here, which at this point contains the previously copied .txt files. find finds these files and tries to copy them to the same directory, thus causing said error.

To avoid this, you could exclude the ./copy_here directory from find:

find -type f -name "*.txt" ! -path "./copy_here*" -exec cp {} ./copy_here \;

(there are several other ways to exclude directories and patterns, too)

or tell cp not to overwrite existing files:

find -type f -name "*.txt" cp -n ./copy_here {} \;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .