我有两个具有相似布局的目录树,即
. |-- dir1 | |-- a | | |-- file1.txt | | `-- file2.txt | |-- b | | `-- file3.txt | `-- c | `-- file4.txt `-- dir2 |-- a | |-- file5.txt | `-- file6.txt |-- b | |-- file7.txt | `-- file8.txt `-- c |-- file10.txt `-- file9.txt
我想合并dir1和dir2目录树来创build:
merged/ |-- a | |-- file1.txt | |-- file2.txt | |-- file5.txt | `-- file6.txt |-- b | |-- file3.txt | |-- file7.txt | `-- file8.txt `-- c |-- file10.txt |-- file4.txt `-- file9.txt
我知道我可以使用“cp”命令来做到这一点,但我想移动文件而不是复制,因为我想合并的实际目录非常大,并且包含大量文件(数百万)。 如果我使用“MV”,由于冲突的目录名称,我得到“文件存在”错误。
更新:您可以假定两个目录树之间没有重复的文件。
rsync -ax --link-dest=dir1/ dir1/ merged/ rsync -ax --link-dest=dir2/ dir2/ merged/
这将创build硬链接而不是移动它们,您可以validation它们是否正确移动,然后删除dir1/
和dir2/
。
奇怪的是,没有人注意到cp
有选项-l
:
-l, - 链接 硬链接文件而不是复制
你可以做类似的事情
%mkdir合并 %cp -rl dir1 / * dir2 / *合并 %rm -r dir * %树合并 合并 ├──a │├──file1.txt │├──file2.txt │├──file5.txt │└──file6.txt ├──b │├──file3.txt │├──file7.txt │└──file8.txt └──c ├──file10.txt ├──file4.txt └──file9.txt 13个目录,0个文件
你可以使用重命名(又名,来自perl包)。 注意这个名字并不一定是指我在debian / ubuntu之外描述的命令(尽pipe如果你需要的话它是一个单独的可移植的perl文件)。
mv -T dir1 merged rename 's:^dir2/:merged/:' dir2/* dir2/*/* find dir2 -maxdepth 1 -type d -empty -delete
您还可以select使用vidir(来自moreutils),并从首选文本编辑器编辑文件path。
我喜欢rsync和prename的解决scheme,但是如果你真的想让mv做这个工作和
-print0
和-depth
, -0
, 那么可以处理大量可能在其名称中都有随机空格的文件,所有这些都使用Bourne风格的shell脚本:
#!/bin/sh die() { printf '%s: %s\n' "${0##*/}" "$*" exit 127 } maybe='' maybe() { if test -z "$maybe"; then "$@" else printf '%s\n' "$*" fi } case "$1" in -h|--help) printf "usage: %s [-n] merge-dir src-dir [src-dir [...]]\n" "${0##*/}" printf "\n Merge the <src-dir> trees into <merge-dir>.\n" exit 127 ;; -n|--dry-run) maybe=NotRightNow,Thanks.; shift ;; esac test "$#" -lt 2 && die 'not enough arguments' mergeDir="$1"; shift if ! test -e "$mergeDir"; then maybe mv "$1" "$mergeDir" shift else if ! test -d "$mergeDir"; then die "not a directory: $mergeDir" fi fi xtrace='' case "$-" in *x*) xtrace=yes; esac for srcDir; do (cd "$srcDir" && find . -print0) | xargs -0 sh -c ' maybe() { if test -z "$maybe"; then "$@" else printf "%s\n" "$*" fi } xtrace="$1"; shift maybe="$1"; shift mergeDir="$1"; shift srcDir="$1"; shift test -n "$xtrace" && set -x for entry; do if test -d "$srcDir/$entry"; then maybe false >/dev/null && continue test -d "$mergeDir/$entry" || mkdir -p "$mergeDir/$entry" continue else maybe mv "$srcDir/$entry" "$mergeDir/$entry" fi done ' - "$xtrace" "$maybe" "$mergeDir" "$srcDir" maybe false >/dev/null || find "$srcDir" -depth -type d -print0 | xargs -0 rmdir done
蛮力bash
#! /bin/bash for f in $(find dir2 -type f) do old=$(dirname $f) new=dir1${old##dir2} [ -e $new ] || mkdir $new mv $f $new done
testing做到这一点
# setup for d in dir1/{a,b,c} dir2/{a,b,c,d} ; do mkdir -p $d ;done touch dir1/a/file{1,2} dir1/b/file{3,4} dir2/a/file{5,6} dir2/b/file{7,8} dir2/c/file{9,10} dir2/d/file11 # do it and look $ find dir{1,2} -type f dir1/a/file1 dir1/a/file2 dir1/a/file5 dir1/a/file6 dir1/b/file3 dir1/b/file7 dir1/b/file8 dir1/c/file4 dir1/c/file9 dir1/c/file10 dir1/d/file11
在不同的开发阶段,我不得不这样做几次源代码树。 我的解决scheme是以如下方式使用Git:
你可以用分支等等来巧妙地devise它,但是这是一般的想法。 而且由于每个状态都有完整的快照,所以你不用担心填充它。