使用 Rsync 检测目录移动

使用 Rsync 检测目录移动

我当前用于将一个硬盘备份到另一个硬盘(本地,而不是远程)的命令是

rsync \
    --info=PROGRESS2,BACKUP,DEL \
    -ab \
    --human-readable \
    --inplace \
    --delete-after \
    --debug=NONE \
    --log-file=/media/blueray/WDPurple/rsync.log \
    --backup-dir=red_rsync_bak.$(date +"%d-%m-%y_%I-%M-%S%P") \
    --log-file-format='%t %f %o %M' \
    --exclude='lost+found' \
    --exclude='.Trash-1000' \
    /media/blueray/WDRed \
    /media/blueray/WDPurple

如果我使用--delete-afterrsync,则将移动的目录视为已删除和创建的目录。

因此,当我在源中移动目录时,它会从目标中删除这些目录,然后从源中复制它们。通常需要很长时间,因为我有时会在源中移动大型目录。

我发现这个问题的解决方案很少。

  1. 补丁rsync

  2. 没有补丁

  3. 使用 BorgBackup 或 bup

  4. 使用--fuzzy --delay-updates --delete-delay

然而,每个人都有自己的问题。

该补丁是很久以前创建的,我不确定它是否会对现代 rsync 产生问题。而且,维护补丁对我来说很困难。

选项二会使我的硬盘变得混乱。此外,我使用了更多rsync选项,不确定它是否安全。

就选项 3 而言,我投入了大量时间rsync,现在不想转向新工具。此外,这些工具也有自己的问题。

关于选项 4,使用 /test/10GBfile 重命名--fuzzy --delay-updates --delete-delay为 /test/otherdir/10GBfile_newname 仍会重新发送数据,因为它不在同一目录中。它还有很多问题。前任。--delay-updates与 冲突--inplace

所以,我正在寻找的解决方案是使用--itemize-changes--dry-run获取移动的目录列表,然后首先mv在目标中运行(如果有类似 x will be moving to a/x in destinition, y will be moving to b/y in destinition,c/z 的提示那就太好了将被移动到目的地中的 z 。您想继续吗?),然后运行我rsync在顶部提到的命令。我准备考虑与类似目录具有相同名称和大小的目录。

假设目录树如下所示:

.
├── dest
│   ├── test
│   │   └── empty-asciidoc-document.adoc
│   ├── test2
│   │   └── empty-asciidoc-document.adoc
│   └── test3
│       └── empty-asciidoc-document.adoc
├── src
│   ├── grandpartest1
│   │   └── partest
│   │       └── test1
│   │           └── empty-asciidoc-document.adoc
│   ├── grandpartest2
│   │   └── partest2
│   │       └── test2
│   │           └── empty-asciidoc-document.adoc
│   └── grandpartest3
│       └── partest3
│           └── test3
│               └── empty-asciidoc-document.adoc

我注意到如果我移动目录,--itemize-changes输出看起来像:

% rsync --dry-run -ai --inplace --delete-after /home/blueray/Downloads/src/ /home/blueray/Downloads/dest/
.d..t...... ./
cd+++++++++ grandpartest/
cd+++++++++ grandpartest/partest/
cd+++++++++ grandpartest/partest/test/
>f+++++++++ grandpartest/partest/test/empty-asciidoc-document.adoc
cd+++++++++ grandpartest2/
cd+++++++++ grandpartest2/partest2/
cd+++++++++ grandpartest2/partest2/test2/
>f+++++++++ grandpartest2/partest2/test2/empty-asciidoc-document.adoc
cd+++++++++ grandpartest3/
cd+++++++++ grandpartest3/partest3/
cd+++++++++ grandpartest3/partest3/test3/
>f+++++++++ grandpartest3/partest3/test3/empty-asciidoc-document.adoc
*deleting   test3/empty-asciidoc-document.adoc
*deleting   test3/
*deleting   test2/empty-asciidoc-document.adoc
*deleting   test2/
*deleting   test/empty-asciidoc-document.adoc
*deleting   test/

我们可以使用以下方法获取已删除的目录:

% echo "$dryrunoutput" | grep "*deleting.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done
test3
test2
test

添加目录使用:

% echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done | while read spo; do echo ${spo##*/}; done
grandpartest
partest
test
grandpartest2
partest2
test2
grandpartest3
partest3
test3

使用以下命令添加和删除的目录:

$ sort  <(echo "$deletedirectories") <(echo "$addeddirectoriesvalue") | uniq -d
test
test2
test3

目录大小(以字节为单位),比较两个相同的目录(或多或少,这对我有用),使用:

% /usr/bin/du -sb "/home/blueray/Documents/src/test2/test" | grep -oh "^\S*"
4096
% /usr/bin/du -sb "/home/blueray/Documents/dest/test" | grep -oh "^\S*"
4096

到目前为止我想出的脚本是:

#!/bin/bash

source="/media/blueray/WDRed/_working/_scripts/_rsync-test/src/"
destination="/media/blueray/WDRed/_working/_scripts/_rsync-test/dest/"
dryrunoutput=$(rsync --dry-run -ai --inplace --delete-after $source $destination)
deletedirectories=$( echo "$dryrunoutput" | grep "*deleting.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done )
addeddirectorieskey=$( echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done )
addeddirectoriesvalue=$( echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done | while read spo; do echo ${spo##*/}; done )

intersection=$( sort  <(echo "$deletedirectories") <(echo "$addeddirectoriesvalue") | uniq -d )

sourcesize=$(/usr/bin/du -sb "${source}test2/test" | grep -oh "^\S*")

destsize=$(/usr/bin/du -sb "${destination}test" | grep -oh "^\S*")

if [[ "$destsize" == "$sourcesize" ]]
then
  mv "${destination}test/" "$destination$addeddirectories"
fi

如果您注意到mv "${destination}test/" "$destination$addeddirectories",这里的部分路径是硬编码的。它还存在其他问题。它仅适用于单个目录和类似的东西。

聚苯乙烯我知道相似的名称和大小并不意味着它们相同,但就我而言,它会起作用。我的目录是主要问题,文件不是。所以,我并不真正担心文件移动检测。我只对目录移动检测感兴趣。

答案1

您可以使用它作为备份的基础。它要求源文件系统和目标文件系统可以处理硬链接文件,并且您不介意目标文件在运行之间保持硬链接到工作目录。写出文件 inode 和相对路径的选项find依赖于 GNU 版本。-printf

#!/bin/bash
# Usage: [<rsync_args...>] <src> <dst> 
#
args=("$@")
src="${args[-2]}"          # '.'
dst="${args[-1]}"          # eg 'remote:/tmp/dest'
unset args[-1] args[-1]    # Yes really


# Create the working set space
#
temp=".inodes"
mkdir -p "$src/$temp"


# Build the set of files indexed by inode
#
echo Create inodes >&2
find "$src" -path "$src/$temp" -prune -o -type f -printf "%i\t%P\0" |
    while IFS= read -d '' -r line
    do
        inode="${line%%$'\t'*}" file="${line#*$'\t'}"
        ln -f "$src/$file" "$src/$temp/$inode"
    done


# Copy the index and then the full tree
#
echo Copy inodes >&2
rsync -avPR "${args[@]}" "$src/./$temp/" "$dst/"

echo Copy structure >&2
rsync -avHPR --delete-after "${args[@]}" "$src/./$temp/" "$src/./" "$dst/"


# Remove the working set on the source (not essential but you may prefer it)
#
echo Tidyup >&2
rm -rf "$src/$temp"

如果你调用它dsync并将其放入你的路径中,你可以像这样使用它

dsync /media/blueray/WDRed /media/blueray/WDPurple

或潜在地

dsync --info=PROGRESS2,BACKUP,DEL --backup --human-readable --inplace --delete-after --log-file=/media/blueray/WDPurple/rsync.log --backup-dir=red_rsync_bak.$(date +"%d-%m-%y_%I-%M-%S%P") --log-file-format='%t %f %o %M' --exclude='lost+found' --exclude='.Trash-1000' /media/blueray/WDRed /media/blueray/WDPurple

相关内容