我的错误命令:
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)