“find -exec mv”尝试移动之前移动的同一文件

“find -exec mv”尝试移动之前移动的同一文件

我的错误命令:

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

结果 :

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

我认为它找到了之前移动的文件。我可以在不使用 maxdepth 的情况下解决这个问题吗?有没有办法只排除目标目录?

答案1

您应该忽略要排除的目标目录

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

运算符之间的隐式 AND 比 OR ( -o) 绑定得更紧密,因此它可以翻译为(如果路径匹配则跳过./backup_2019)或者(mv如果我们有匹配的文件*2019*

答案2

您需要忽略备份目录,以免find进入其中。已经有一个答案展示如何做到这一点。

但是,如果您以这种方式备份文件,则可能会面临删除数据的风险。如果不同子目录中的两个或多个文件具有相同的名称,它们将在目标备份目录中相互覆盖。

最好使用一些真正的备份软件来备份数据,例如restic。如果这不可能,请使用保留要备份的文件的相对路径的解决方案。

以下命令用于rsync将名称包含子字符串的所有文件复制(而不是移动)2019到目录中backup_2019

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

这将避免在内部查找./backup_2019要传输的文件或目录,但会复制包含子字符串的所有内容2019。目标上最终为空的目录将被删除。复制的所有内容都将复制到backup_2019与当前目录下的文件位置相同的位置:

例子:

$ 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

您可以添加--remove-source-files到选项列表中rsync以对备份的文件执行“移动”而不是“复制”。

答案3

如果您还没有找到解决方案,请尝试 maxdepth 选项。或者尝试备份到不是当前搜索的子文件夹的其他文件夹。

前发现。 -最大深度1 -名称“2019年“ -exec mv '{}' ./backup_2019 ;

答案4

嗯,这是一个意想不到的坏惊喜。无论如何,你可以忘记-exec并尝试其他事情。

find . -type f -name '*2019*' -print0 | while read -d $'\0' fpath; do mv "$fpath" ./backup_2019; done

在这里,我添加-print0-d $'\0'以空字符代替空格(默认)作为分隔符,以便脚本支持其中包含空格的文件名。

当您使用管道时,您正在创建子 shell 并失去对“全局”脚本变量的访问。

如果您需要访问循环内的“全局变量”,那么您可以使用进程替换而不是管道。

myvar=""
while read -d $'\0' fpath 
do 
  mv "$fpath" ./backup_2019
  myvar="Hello World" 
done < <(find . -type f -name '*2019*' -print0)

相关内容