让 macOS 更好地合并同名文件夹

以往我在 Windows 下整理 NAS 上的文件时,遇到需要合并的同名文件夹时,只需要简单地把其中一个拖入到另一个文件夹所在的目录中。如若没有遇到同名文件冲突的情况,那么整个过程会在一瞬间完成,它时十分符合操作直觉的。

但在 macOS 下想要像这样合并两个文件夹却是意外地困难。

在 macOS 下,Finder 默认只为同名文件夹冲突提供了“停止”与“替换”两个选择,无须怀疑,这里的“替换”并没有字面之外意思。而在一番搜索后,不难会发现苹果设置了一个可以用 opt 键触发的隐藏的“合并”按钮。

但这个“合并”始终是以拷贝的形式进行的,这意味着每一次合并文件夹的时候 Finder 都会制造一次毫无意义的磁盘写入。而这份无意义的写入所造成的影响对于 NAS 用户来说,则会被传输协议、磁盘性能、网络带宽等因素进一步放大,最后从无意义进化成了一种折磨

对此,如果不愿意选择那些更迎合 Windows 使用习惯的第三方文件管理器的话,使用跟 Finder 高度耦合的 Automator 来跑一个合并行为更接近 Windows 的脚本可以算是一个折中办法。

Automator 能够很方便得透过 Finder 获取所选文件的路径,同时它也能调用 Finder 的弹窗选择器来手动选择一个路径来作为变量使用。像是这样:

upload successful

在运行工作流的时候,所有被选择的项目的路径都会依序作为列表值被输入,而在通过请求访达项目选择输出路径后,就得到了一个类似 ['-c', 'path1', 'path2', 'path3',...'pathN'] 的列表。起始项始终是固定的值 '-c',所以此处只需要截取第二项至倒数第二项作为 src,以及结尾项作为 dst 即可。

有了 srcdst ,事情就变得非常简单了,这里就用 Python 的 shutil 模块起一个脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sys,os,shutil

src = sys.argv[1:-1]
dst = sys.argv[-1]

for item in src:
for root,dirs,files in os.walk(item):
for file in files:
old = os.path.join(root,file)
start = os.path.dirname(item.rstrip('/'))
new = os.path.join(dst,os.path.relpath(old,start))
if not os.path.exists(os.path.dirname(new)):
os.makedirs(os.path.dirname(new))
shutil.move(old,new)
shutil.rmtree(item)

现在将脚本拖入工作流,传递输入选择“作为自变量”,再把脚本的输出作为文本导出一份,最后这个样子就大抵堪用了。

upload successful

最后来验证一下,看起来没有问题

upload successful