当文件已经在两边时,有什么方法可以同步目录结构?

Dan*_*Dan 26 shell directory synchronization

我有两个驱动器具有相同的文件,但目录结构完全不同。

有没有办法“移动”目标端的所有文件,使它们与源端的结构相匹配?也许用脚本?

例如,驱动器 A 具有:

/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt
Run Code Online (Sandbox Code Playgroud)

而驱动器 B 具有:

/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt
Run Code Online (Sandbox Code Playgroud)

有问题的文件很大(800GB),所以我不想重新复制它们;我只想通过创建必要的目录和移动文件来同步结构。

我正在考虑一个递归脚本,它会在目标上找到每个源文件,然后将其移动到匹配的目录,如有必要,创建它。但是——这超出了我的能力!

这里给出了另一个优雅的解决方案:https : //superuser.com/questions/237387/any-way-to-sync-directory-structure-when-the-files-are-already-on-both-sides/238086

Jan*_*nus 11

我会和 Gilles 一起去,并按照hasen j 的建议将你指向 Unison 。Unison 是 DropBox 早于 DropBox 20 年。很多人(包括我自己)每天都在使用的坚如磐石的代码——非常值得学习。尽管如此,join它仍然需要得到所有的宣传:)


这只是一半的答案,但我必须回去工作:)

基本上,我想演示一个鲜为人知的join实用程序,它就是这样做的:在某个字段上连接两个表。

首先,设置一个包含带空格的文件名的测试用例:

for d in a b 'c c'; do mkdir -p "old/$d"; echo $RANDOM > "old/${d}/${d}.txt"; done
cp -r old new
Run Code Online (Sandbox Code Playgroud)

(在 中编辑一些目录和/或文件名new)。

现在,我们要为每个目录构建一个映射:hash -> filename,然后用于join匹配具有相同散列的文件。要生成地图,请将以下内容放入makemap.sh

find "$1" -type f -exec md5 -r "{}" \; \
  | sed "s/\([a-z0-9]*\) ${1}\/\(.*\)/\1 \"\2\"/" \
Run Code Online (Sandbox Code Playgroud)

makemap.sh 吐出一个文件的形式为'hash "filename"',所以我们只加入第一列:

join <(./makemap.sh 'old') <(./makemap.sh 'new') >moves.txt
Run Code Online (Sandbox Code Playgroud)

这将生成moves.txt如下所示:

49787681dd7fcc685372784915855431 "a/a.txt" "bar/a.txt"
bfdaa3e91029d31610739d552ede0c26 "c c/c c.txt" "c c/c c.txt"
Run Code Online (Sandbox Code Playgroud)

下一步将是实际操作,但我的尝试被困在引用上……mv -i而且mkdir -p应该会派上用场。


has*_*sen 8

有一个名为 unison 的实用程序:

http://www.cis.upenn.edu/~bcpierce/unison/

来自网站的描述:

Unison 是一个用于 Unix 和 Windows 的文件同步工具。它允许文件和目录集合的两个副本存储在不同主机(或同一主机上的不同磁盘)上,分别修改,然后通过将每个副本中的更改传播到另一个副本来更新。

请注意,如果至少有一个根是远程的,Unison 仅在第一次运行时检测移动的文件,因此即使您正在同步本地文件,也请ssh://localhost/path/to/dir用作根之一。


ale*_*lex 1

像这样的事情怎么样:

src=/mnt/driveA
dst=/mnt/driveB

cd $src
find . -name <PATTERN> -type f >/tmp/srclist
cd $dst
find . -name <PATTERN> -type f >/tmp/dstlist

cat /tmp/srclist | while read srcpath; do
    name=`basename "$srcpath"`
    srcdir=`dirname "$srcpath"`
    dstpath=`grep "/${name}\$" /tmp/dstlist`

    mkdir -p "$srcdir"
    cd "$srcdir" && ln -s "$dstpath" "$name"
done
Run Code Online (Sandbox Code Playgroud)

这假设您要同步的文件的名称在整个驱动器中是唯一的:否则无法完全自动化(但是,如果有多个文件,您可以提示用户选择要选择的文件。)

上面的脚本可以在简单的情况下工作,但如果name碰巧包含对正则表达式具有特殊含义的符号,则可能会失败。如果文件很多,文件列表grep也可能会花费很多时间。您可以考虑将此代码转换为使用哈希表,它将文件名映射到路径,例如在 Ruby 中。