在我的 Google Filestream、Google Drive 和 Synology CloudSync 之间同步时,一切都变得混乱了,我留下了数百个重复的文件夹,文件夹名称后跟“(1)”或“(2)”等,一直到“(1) (1) (1)”。
您知道可以合并这些文件夹的程序或脚本吗?
顶级文件夹结构示例:
1100 Beetledwarf - Happy ATE
1100 Beetledwarf - Happy ATE (1)
1100 Beetledwarf - Happy ATE (2)
1100 Beetledwarf - Happy ATE (3)
1100 Beetledwarf - Happy ATE (3) (1)
1100 Beetledwarf - Happy ATE (3) (1) (1)
1100 Beetledwarf - Happy ATE (4)
1100 Beetledwarf - Happy ATE (5)
1100 Beetledwarf - Happy ATE (6)
由于子文件夹有时也存在同样的问题,因此程序或脚本需要能够合并遵循所有子文件夹命名模式的文件夹,例如:
第二级文件夹示例:
1100 Beetledwarf - Happy ATE (6) Analysis Analysis (1) Smirckle_HL Smirckle_HL (2) Pending Reports Photos & Logos
最好的解决方案还允许我移动文件而不是复制文件,因为复制文件需要很长时间,但移动几乎是即时的。
我已经尝试过的方法列表,但它们都无法处理“名称(1)”文件夹结构(到目前为止我可以说的),并且它们都复制文件而不是移动它们:
- Windows 10 版 WinMerge <- 尝试复制 Google Drive 文件时发生故障(返回类似“不支持 DOS 命令”的内容)
- Meld for MacOS。<- 慢。
- OS X 中带有“ditto”命令的终端<-迄今为止最佳选择。
感谢您的帮助!
答案1
这是我在 Linux 中尝试的方法。我没有使用过 Google Filestream、Google Drive 或 Synology CloudSync,所以我无法判断该解决方案是否可行。不过我希望这至少能给你一些启发。
假设
- 您可以在目录树中挂载共享,因此
mv
,cp
和其他合理工具可以像处理本地目录一样处理目录; - 删除所有
(N)
字符串后路径变得相同的文件(或目录)实际上是同一个文件(目录)的实例; - 同一个文件的实例应该只留下一个文件;
- 同一目录的实例应将其内容合并到一个目录中;
- 您可以使用我在这里使用的所有工具。
程序
在尝试做任何事情之前,请阅读整个答案。
我认为有些步骤可以写成脚本,但由于解决方案是高度实验性,最好是手工一步一步地做,注意发生的情况。
在 shell 中
cd
进入挂载点并调用find . | vidir -
;使用您选择的文本编辑器,例如kate
,如下所示:find . | EDITOR=kate vidir
这将打开编辑器,其中包含所有对象的列表,每个对象前面都有自己的编号。当您更改内容并保存(临时)文件并关闭编辑器时,所有更改都会应用。一般来说,您可以执行以下操作:
- 改变路径来移动(重命名)文件或目录;
- 删除行以删除文件或目录;
- 交换两个或多个数字来交换文件(你不需要它)。
除非您确定新内容描述了您想要获取的目录树,否则不要保存文件。
将内容从编辑器复制到其他文件。关键是要使用它,只有当您确定正确时才粘贴结果(并保存)。除非另有明确说明,否则后续步骤将参考新文件。
使用
sed
或任何其他工具删除所有(N)
字符串(注意前导空格)。此时您应该获得“干净”的路径,其中许多路径会出现多次(由 给出不同的数字vidir
)。使用
sort -k 2
根据这些路径进行排序。由于-s
前者Analysis
仍然应该在前者之前Analysis (1)
。用于
uniq -f 1
删除重复的路径。现在任何路径都只应出现一次。仔细检查结果中编码的目录结构的健全性。
将结果粘贴到原始编辑器中,保存文件并退出编辑器。
vidir
将删除与缺失数字相关的对象并移动与剩余数字相关的对象。
测试
我会首先使用此解决方案复制目录结构:
cp -a --attributes-only /mountpoint/ /guinea_pig_dir/
并在生成的空文件上测试该过程。这应该会发现问题(如果有的话),并有望改进该方法。
可能出现的问题
vidir
拒绝使用一些非标准字符。一般来说,对象的顺序很重要。当与发生冲突时,生成像
foo~
或 这样的对象时foo~1
,会出现一些陷阱。您将以一种不会产生冲突的方式“收缩”目录树,但我还没有调查所有可能的情况。我真的认为你应该尝试一下,看看会得到什么。如果遇到麻烦foo~2
foo
/guinea_pig_dir/
或许巧妙的sort
介于find
和之间vidir
将会有所帮助。
答案2
下面是执行此任务的 bash 脚本。它适用于添加了 rsync 的 MSYS2 Bash。它取自此处的相关问题:
#!/usr/bin/bash
IFS=$'\n';
set -f
#Go deepest first to deal with copies within copied folders.
for copy in $(find . -regextype posix-egrep -regex "^.*\ \([0-9]+\)\s*(\.[^/.]*)?$" | awk '{print length($0)"\t"$0}' | sort -rnk1 | cut -f2-); do
orig=$(rev <<< "$copy" | sed -E 's/\)[0-9]+\(\ //' | rev)
if [ "$orig" != "$copy" ]; then
if [ -f "$orig" ]; then
if [ -f "$copy" ]; then
echo "File pair: $orig $copy"
if diff -q "$orig" "$copy" &>/dev/null; then
echo "Removing file: $copy"
rm -f "$copy";
fi
fi
fi
if [ -d "$orig" ]; then
if [ -d "$copy" ]; then
echo "Folder pair: $orig $copy"
if rmdir "$copy" &>/dev/null; then
#If the "copy" was an empty directory then we've removed it and so we're done.
echo "Removed empty folder: $copy"
else
#Non-destructively ensure that both folders have the same files at least.
rsync -aHAv --ignore-existing "$orig/" "$copy" &>/dev/null
rsync -aHAv --ignore-existing "$copy/" "$orig" &>/dev/null
if diff -qr "$orig" "$copy" &>/dev/null; then
echo "Removing folder: $copy"
rm -rf "$copy";
fi
fi
fi
fi
fi
done
unset IFS;
set +f
答案3
以下脚本可以在 OS X 上运行,但存在一些问题:
有时 Google 文档无法复制,因此文件夹无法通过差异测试,因此不会被删除。然后我必须手动对它们运行差异测试,检查差异是否都是 Google 文档,如果 Google 文档不在原始文件夹中,则手动将 Google 文档移动到原始文件夹中,然后手动删除重复的文件夹。(注意:从 Finder 中我无法复制相同的文档,这对我来说似乎很奇怪,因为我觉得我以前复制过(或选择 + 拖动)Google 文档文件。)
#!/usr/bin/bash
IFS=$'\n';
set -f
#Go deepest first to deal with copies within copied folders.
for copy in $(find -E . -regex "^.*\ \([0-9]+\)\s*(\.[^/.]*)?$" | awk '{print length($0)"\t"$0}' | sort -rnk1 | cut -f2-); do
orig=$(rev <<< "$copy" | sed -E 's/\)[0-9]+\(\ //' | rev)
if [ "$orig" != "$copy" ]; then
if [ -f "$orig" ]; then
if [ -f "$copy" ]; then
echo "File pair: $orig $copy"
if diff -q "$orig" "$copy" &>/dev/null; then
echo "Removing file: $copy"
rm -f "$copy";
fi
fi
fi
if [ -d "$orig" ]; then
if [ -d "$copy" ]; then
echo "Folder pair: $orig $copy"
if rmdir "$copy" &>/dev/null; then
#If the "copy" was an empty directory then we've removed it and so we're done.
echo "Removed empty folder: $copy"
else
#Non-destructively ensure that both folders have the same files at least.
rsync -aHAv --ignore-existing "$orig/" "$copy" &>/dev/null
rsync -aHAv --ignore-existing "$copy/" "$orig" &>/dev/null
if diff -x ‘.*’ -x 'Icon?' -qr "$orig" "$copy" &>/dev/null; then
echo "Removing folder: $copy"
trash -v "$copy" # requires that Ali Rantakari's app is installed: aka that you have already run 'brew install trash'
#replaced the following: rm -rf "$copy";
fi
fi
fi
fi
fi
done
unset IFS;
set +f
注意:此项工作可能依赖于安装以下工具,详见本页:https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install coreutils
export PATH="$(brew --prefix coreutils)/libexec/gnubin:/usr/local/bin:$PATH"
brew tap homebrew/dupes
brew install binutils
brew install diffutils
brew install ed --with-default-names
brew install findutils --with-default-names
brew install gawk
brew install gnu-indent --with-default-names
brew install gnu-sed --with-default-names
brew install gnu-tar --with-default-names
brew install gnu-which --with-default-names
brew install gnutls
brew install grep --with-default-names
brew install gzip
brew install screen
brew install watch
brew install wdiff --with-gettext
brew install wget
brew install bash
brew install rsync