mv
を使用して「folder」という名前のフォルダを、すでに「folder」が含まれているディレクトリに移動すると、それらはマージされるか、それとも置き換えられますか?
mv
はディレクトリをマージまたは上書きできません。メッセージ "mv:cannot a move a 'b':Directory not empty"を使用していても失敗します。 --force
オプション。
他のツール(rsync
、find
、またはcp
など)を使用してこれを回避できますが、その影響を慎重に検討する必要があります。
rsync
は、あるディレクトリの内容を別のディレクトリにマージできます(理想的には、--remove-source-files
1 正常に転送されたソースファイルのみを安全に削除するオプション、および通常の権限/所有権/時間保持オプション-a
(必要な場合)rsync
の--link-dest=DIR
オプション(可能な場合はファイルの内容をコピーする代わりにハードリンクを作成する)と--remove-source-files
を組み合わせて、通常のmv
。--link-dest
には、sourceディレクトリへの絶対パス(または宛先からの相対パスsource)に.--link-dest
を使用しているため(複雑化を引き起こす可能性があります)、知っている(または決定する)ソースへの絶対パス(--link-dest
への引数として)、および空のディレクトリ構造を残してクリーンアップします。 1。find
を使用して、ターゲットでソースディレクトリ構造を順次再作成し、実際のファイルを個別に移動できますcp
はハードリンクを作成できます (単純に言えば、同じ既存のファイルへの追加のポインター)。これは、マージmv
と非常に似た結果を作成します(ポインターのみが作成され、実際のデータをコピーする必要があります)これらの回避策(存在する場合)のうちどれが適切かは、特定のユースケースに大きく依存します。
いつものように、これらのコマンドを実行する前に考えて、バックアップを作成してください。
1:rsync --remove-source-files
はディレクトリを削除しないことに注意してください。空のソースディレクトリツリーを削除するには、後でfind -depth -type d -empty -delete
のような処理を行う必要があります。
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
cpコマンドの-l
オプションを使用して、フルファイルではなく、同じファイルシステム上に ハードリンク のファイルを作成できます。データのコピー。次のコマンドは、フォルダーsource/folder
を、destination
という名前のディレクトリが既に含まれている親フォルダー(folder
)にコピーします。
cp -rl source/folder destination
rm -r source/folder
また、必要に応じて、-P
(--no-dereference
-シンボリックリンクを逆参照しない)または-a
(--archive
--P
オプションも含めてすべてのメタデータを保持する)を使用することもできます。
次の4つのステップをお勧めします。
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
さらに良いことに、mv
と同様のセマンティクスを実装するスクリプトは次のとおりです。
#!/bin/bash
DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"
for SRC in ${@:1:$((${#@} -1))}; do (
cd "$SRC";
find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
find . -type d -empty -delete
) done
これは、ディレクトリをマージする方法です。ファイルをコピーして削除するのではなく、ファイル名を変更するだけなので、rsyncよりもはるかに高速です。
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
これを達成する1つの方法は、以下を使用することです。
mv folder/* directory/folder/
rmdir folder
folder
とdirectory/folder
で同じ名前のファイルが2つない限り、マージなどの同じ結果が得られます。
最も純粋なコピーの場合、私はtar(-)B blockread copyメソッドを使用します。
例、ソースパス内から(必要に応じてそこに「cd」):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
これにより、所有者と権限はそのままで、ソースツリーの正確なコピーが作成されます。そして、ターゲットフォルダが存在する場合、データはマージされます。既存のファイルのみが上書きされます。
例:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
コピーアクションが成功したら、ソース(rm -rf <source>
)を削除できます。もちろん、これは正確な移動ではありません。ソースを削除するまで、データはコピーされます。
オプションとして、-vを使用して詳細(コピーするファイルを画面に表示)にすることができます:tar cBvf -
c
:作成B
:完全なブロックを読み取る(パイプ読み取りの場合)v
:詳細f
:書き込むファイルx
:抽出-
:stdout/stdinsourcefolder
は*
にすることもできます(現在のフォルダー内のすべてのもの)
これは私のために働いたスクリプトです。私はrsyncよりもmvを好むので、JewelおよびJonathan Mayerのソリューションを使用します。
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in "$sources"; do
pushd "$SRC";
find . -type d -exec mkdir -p "${DEST}/{}" \;
find . -type f -exec mv {} "${DEST}/{}" \;
find . -type d -empty -delete
popd
done
Cpやrsyncなどのコマンドを使用することはお勧めできません。大きなファイルの場合は時間がかかります。 mvは、ファイルを物理的にコピーせずにiノードを更新するだけなので、はるかに高速です。オペレーティングシステムのファイルマネージャーを使用することをお勧めします。 opensuseの場合、Konquererと呼ばれるファイルマネージャーがあります。実際にコピーせずにファイルを移動できます。 Windows同様、「カット&ペースト」機能を搭載。ディレクトリAのすべてのサブディレクトリを選択するだけです。右クリックして、同じ名前のサブディレクトリが含まれている可能性があるディレクトリBに「移動」します。それらをマージします。同じ名前のファイルを上書きするか、名前を変更するかを選択するオプションもあります。
Pythonソリューション
満足できる既存のソリューションを見つけることができなかったので、すぐにPythonスクリプトを作成してそれを実現しました。
特に、この方法はソースファイルツリーを1度ボトムアップするだけなので、効率的です。
また、ファイルの上書き処理などを好みに合わせてすばやく調整することもできます。
使用法:
move-merge-dirs src/ dest/
src/*
のすべてのコンテンツがdest/
に移動し、src/
が消えます。
move-merge-dirs
#!/usr/bin/env python3
import argparse
import os
def move_merge_dirs(source_root, dest_root):
for path, dirs, files in os.walk(source_root, topdown=False):
dest_dir = os.path.join(
dest_root,
os.path.relpath(path, source_root)
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
for filename in files:
os.rename(
os.path.join(path, filename),
os.path.join(dest_dir, filename)
)
for dirname in dirs:
os.rmdir(os.path.join(path, dirname))
os.rmdir(source_root)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Move merge src/* into dest. Overwrite existing files.'
)
parser.add_argument('src_dir')
parser.add_argument('dest_dir')
args = parser.parse_args()
move_merge_dirs(args.src_dir, args.dest_dir)
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
pushd "$SRC";
# Only one scan - we only need folders with files
find . -type f | while read FILE ; do
DIRNAME=`dirname "$FILE"`
# Create the lowest level directory at once
if [ ! -d "$DEST/$DIRNAME" ] ; then
mkdir -v "$DEST/$DIRNAME"
fi
mv -v "$FILE" "$DEST/$FILE"
done
# Remove the directories no longer needed
find . -type -d | sort -r | xargs -i rmdir "{}"
popd
done
これは、ファイルとフォルダを他の宛先に移動するためのコマンドです。
$ mv /source/path/folder /target/destination/
記憶:フォルダーがb̲e̲i̲n̲g m̲e̲r̲ge̲d̲の場合、mv
コマンドは機能しません(つまり、同じ名前はすでに宛先に存在します)およびd̲e̲s̲t̲i̲n̲a̲t̲i̲o̲n̲ o̲n̲e̲ i̲s̲ n̲o̲t̲ e̲m̲pt̲y。
mv:「/ source/path/folder」を「/ target/destination/folder」に移動できません:ディレクトリが空ではありません
宛先フォルダが空の場合、上記のコマンドは正常に動作します。
したがって、いずれの場合でも両方のフォルダをマージするには、
次の2つのコマンドで実行します。
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
または、両方を1回限りのコマンドとして組み合わせます。
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv =移動
cp =コピー
rm =削除-r(ディレクトリ(フォルダー)の場合)
-f強制実行
aとbを次のようにマージできます:
shopt -s dotglob
mv a/* b
Mvの前:
.
├── a
│ ├── c
│ │ └── x
│ └── .x
└── b
├── y
└── .y
Mvの後:
.
├── a
└── b
├── c
│ └── x
├── .x
├── y
└── .y
dotglob。xのように非表示のドットファイルを移動できます
rmdirを使用して、空のディレクトリを削除します。