同様のレイアウトを持つ2つのディレクトリツリーがあります。
.
|-- 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ディレクトリツリーをマージして作成します。
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」を使用すると、ディレクトリ名が競合するため「ファイルが存在します」というエラーが表示されます。
更新:2つのディレクトリツリーの間に重複ファイルがないと想定できます。
rsync -ax --link-dest=dir1/ dir1/ merged/
rsync -ax --link-dest=dir2/ dir2/ merged/
これにより、ハードリンクが移動するのではなく作成されます。ハードリンクが正しく移動したことを確認してから、dir1/
およびdir2/
を削除できます。
cp
にオプション-l
があることに誰も気づいていないのは奇妙です:
-l、-link ファイルをコピーする代わりにハードリンク
あなたは次のようなことができます
%mkdir merge %cp -rl dir1/* dir2/* merge %rm -r dir * %tree merge merge ├──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の外で説明するコマンドを必ずしも指しているわけではないことに注意してください(必要な場合は、単一の移植可能なPerlファイルです)。
mv -T dir1 merged
rename 's:^dir2/:merged/:' dir2/* dir2/*/*
find dir2 -maxdepth 1 -type d -empty -delete
(moreutilsからの)vidirを使用して、お好みのテキストエディターからファイルパスを編集することもできます。
rsyncとprenameソリューションが好きですが、本当にmvにしたい場合は、
-print0
と-depth
を知っています、-0
を知っています、次に、名前にランダムな空白が含まれている可能性のある多数のファイルを、すべてボーンスタイルのシェルスクリプトで処理できます。
#!/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
テストはこれを行います
# 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
開発のさまざまな段階のソースコードツリーに対して、これを数回実行する必要がありました。私の解決策は、次の方法でGitを使用することでした。
分岐などで細かく調整できますが、これは一般的な考え方です。そして、各状態の完全なスナップショットを持っているので、それを詰めることについての恐れが少なくなります。