Answers:
为了增加Nils的答案(对于通过Google遇到此问题的任何人),默认情况下,rsync
仅比较文件大小和修改时间以判断是否存在差异。(如果这些不同,则执行更多操作,但是如果它们相同,则停止在此处。)
如果要比较实际文件内容,即使对于具有相同大小和最后修改时间的文件,请添加标志-c
以告诉rsync
您使用校验和来比较文件。
rsync -avnc $SOURCE $TARGET
(该-u
选项告诉rsync忽略$TARGET
比on 更新的文件,$SOURCE
如果您要比较内容,则可能不希望看到这些文件。)
--no-group --no-owner --no-perms --no-times
或将这些数据进行某种组合。
-a
代替-a
,例如rsync -rlDcnv --delete $SOURCE $TARGET
--delete
仅存在于$TARGET
只适合那些不太熟悉的人rsync
:
rsync -rvnc --delete ${SOURCE}/ ${DEST}
-n
:最重要的一点-你不能改变任何东西;-rc
:只比较内容(否则用-ac
);-v
:列出文件)--delete
:寻找对称的差异,而不是单向的差异。/
意思是“查看目录,并将其内容与目标进行比较”。它将打印出通常的
rsync
输出,
- 一行中的每个“新”文件都带有一个<filename>
${SOURCE}
并为中的每个“新”文件添加一个“删除<文件名>”行
${DEST}
。它还可能会显示一些警告,例如符号链接的“跳过非常规文件<文件名>”。
PS。我知道这是一个糟糕的PS,但确实是匆忙添加了。不过,我敢打赌,这可能会有用。
find $SOURCE -type f -exec md5sum {} \; | tee source.md5
find $DEST -type f -exec md5sum {} \; | tee dest.md5
如果文件名不包含换行符,则可以对两个*.md5
文件和diff
它们进行排序。(不过,这仅适用于文件;也就是说,不会检测到两侧的空目录。)
令人惊讶的是,六年来没有答案使用该-i
选项或给出了很好的输出,所以在这里我去:
rsync -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L /'
rsync -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R /'
rsync -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'
这是输出示例:
L file-only-in-Left-dir
R file-only-in-right-dir
X >f.st...... file-with-dif-size-and-time
X .f...p..... file-with-dif-perms
注意每行的第一个字符:
L
/ R
表示文件/目录仅出现在L
eft或R
ight目录中。X
意味着该文件出现在两侧,但是是不一样的(在这种情况下,接下来的11个字符给你更多的信息。s
,t
并p
描绘了不同小号 IZE,牛逼 IME和p分别ermissions -更多的信息尝试man rsync
和搜索--itemize-changes
) 。如果还想比较文件的所有者/组/权限,则分别添加选项-o
/ -g
/ -p
。最后请注意,默认情况下,rsync认为两个文件的名称,时间和大小相同时,它们是相同的。这是非常快的,并且在大多数情况下已经足够了,但是如果您想100%确保添加-c
,还可以比较具有相同名称,时间和大小的文件的内容。
这里是。这样称呼它
diff-dirs Left_Dir Right_Dir [options]
上文“您可能希望使用的其他选项”部分中提到的所有选项也适用于此。
#!/bin/bash
# Compare two directories using rsync and print the differences
# CAUTION: options MUST appear after the directories
#
# SYNTAX
#---------
# diff-dirs Left_Dir Right_Dir [options]
#
# EXAMPLE OF OUTPUT
#------------------
# L file-only-in-Left-dir
# R file-only-in-right-dir
# X >f.st...... file-with-dif-size-and-time
# X .f...p..... file-with-dif-perms
#
# L / R mean that the file/dir appears only at the `L`eft or `R`ight dir.
#
# X means that a file appears on both sides but is not the same (in which
# case the next 11 characters give you more info. In most cases knowing
# that s,t,T and p depict differences in Size, Time and Permissions
# is enough but `man rsync` has more info
# (look at the --itemize-changes option)
#
# OPTIONS
#---------
# All options are passed to rsync. Here are the most useful for the purpose
# of directory comparisons:
#
# -c will force comparison of file contents (otherwise only
# time & size is compared which is much faster)
#
# -p/-o/-g will force comparison of permissions/owner/group
if [[ -z $2 ]] ; then
echo "USAGE: $0 dir1 dir2 [optional rsync arguments]"
exit 1
fi
set -e
LEFT_DIR=$1; shift
RIGHT_DIR=$1; shift
OPTIONS="$*"
# Files that don't exist in Right_Dir
rsync $OPTIONS -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L /'
# Files that don't exist in Left_Dir
rsync $OPTIONS -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R /'
# Files that exist in both dirs but have differences
rsync $OPTIONS -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'
我们这样称呼rsync:
rsync -rin ...
我们使用-i
(--itemize-changes
)告诉rsync为包含有关两个目录之间任何差异的信息的每个文件打印一行输出。我们需要-n
抑制rsync的正常行为(即试图通过复制/删除文件来同步两个目录)。我们还需要-r
递归地处理所有文件/子目录。
我们称呼rsync 3次:
第一次调用:打印Dir_B中不存在的文件。我们需要使用--ignore-existing
忽略双方都存在的文件。
rsync -rin --ignore-existing $DIR_A/ $DIR_B/
第二次通话:与之前完全相同,但我们交换了DIR_A / DIR_B的顺序。
第三次通话:最后,我们--existing
只检查两个目录中都出现的文件。
rsync -rin --existing $DIR_A/ $DIR_B/
我花了一些努力才能使它生效。Nils的答案要求$TARGET
以尾随结尾/
,如ジョージ所解释。
这是显式添加结尾的版本/
:
rsync -avun --delete ${TARGET}/ ${SOURCE} | sed -ne 's/^deleting *//p'
这给出了存在于${SOURCE}
目录下但不在目录下的文件列表${TARGET}
。
我sed
在这里使用以删除deleting
输出行中的开头,并仅打印那些行。
我不使用该rsync
选项,-c
因为在我的用例中比较文件内容会慢很多,而在这些情况下仅比较文件大小和修改时间似乎也足够了。我没有理由怀疑我的计算机遭受时钟偏斜问题或某些恶意更改的时间戳记。同样,的结果-c
不能更改删除文件的决定,只能更改更新或保留文件的决定。
我还使用-u
和-a
(而不是-r
),以便以后可以重新使用命令行并将其更改为将选定的目录和文件从复制${SOURCE}
到${TARGET}
,如下所示:
rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET} # copy some files