5

My wrong command :

find . -type f -name '*2019*' -exec mv {} ./backup_2019 \;

result :

mv: ‘./backup_2019/2019-A.txt’ and ‘backup_2019/2019-A.txt’ are the same file
mv: ‘./backup_2019/2019-B.txt’ and ‘backup_2019/2019-B.txt’ are the same file
mv: ‘./backup_2019/2019-C.txt’ and ‘backup_2019/2019-C.txt’ are the same file

I think it finds the file that it previously moved. Can I solve this without using maxdepth? Is there a way to exclude only the target directory?

0
5

You will need to ignore the backup directory so that find does not enter into it. There is already an answer showing how to do this.

However, you may run the risk of deleting data if you back up files in this way. If two or more files, in different subdirectories, have the same names, they would over-write each other on the destination, in the backup directory.

It would be better to use some real backup software to back up the data, such as restic. If that is not possible, use a solution that preserves the relative path to the files that you are backing up.

The following command uses rsync to copy (not move) all files that have names containing the substring 2019 into the directory backup_2019:

rsync --itemize-changes --archive --prune-empty-dirs \
    --exclude='/backup_2019/***' --include='*/' --include='*2019*' --exclude='*' \
    ./ ./backup_2019

This would avoid looking inside ./backup_2019 for files or directories to transfer, but would otherwise copy all things that contains the substring 2019. Directories on the target that end up empty are removed. Everything that is copied is copied into a location under backup_2019 that is the same as the file's location under the current directory:

Example:

$ tree -F
.
|-- dir1/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
|-- dir2/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
`-- dir3/
    |-- file-1
    |-- file-2019-A
    `-- subdir/
        |-- file-2
        `-- file-2019-B
$ rsync --itemize-changes --archive \
    --prune-empty-dirs \
    --exclude='/backup_2019/***' --include='*/' --include='*2019*' --exclude='*' \
    ./ ./backup_2019
cd+++++++++ ./
cd+++++++++ dir1/
>f+++++++++ dir1/file-2019-A
cd+++++++++ dir1/subdir/
>f+++++++++ dir1/subdir/file-2019-B
cd+++++++++ dir2/
>f+++++++++ dir2/file-2019-A
cd+++++++++ dir2/subdir/
>f+++++++++ dir2/subdir/file-2019-B
cd+++++++++ dir3/
>f+++++++++ dir3/file-2019-A
cd+++++++++ dir3/subdir/
>f+++++++++ dir3/subdir/file-2019-B
$ tree -F
.
|-- backup_2019/
|   |-- dir1/
|   |   |-- file-2019-A
|   |   `-- subdir/
|   |       `-- file-2019-B
|   |-- dir2/
|   |   |-- file-2019-A
|   |   `-- subdir/
|   |       `-- file-2019-B
|   `-- dir3/
|       |-- file-2019-A
|       `-- subdir/
|           `-- file-2019-B
|-- dir1/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
|-- dir2/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
`-- dir3/
    |-- file-1
    |-- file-2019-A
    `-- subdir/
        |-- file-2
        `-- file-2019-B

13 directories, 18 files

You may add --remove-source-files to the list of rsync options to perform a "move" rather than "copy" of the files that you back up.

6

You should ignore the target directory you want to exclude

find . -path './backup_2019' -prune -o -type f -name '*2019*' -exec mv {} ./backup_2019 \;

The implicit AND between operators binds more tightly than the OR (-o), so it translates as (skip if the path matches ./backup_2019) OR (mv if we have files matching *2019*).

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.