mvでフォルダーをマージしますか?


149

mv「フォルダ」と呼ばれるフォルダを「フォルダ」を既に含むディレクトリに移動するために使用する場合、それらはマージされるか、置き換えられますか?

回答:


120

mvディレクトリをマージまたは上書きすることはできません--force。オプションを使用している場合でも、メッセージ「mv: 'a'を 'b'に移動できません:ディレクトリが空ではありません」で失敗します。


あなたは他のツール(のように使用してこの問題を回避することができrsyncfindまたはさえcp)を、しかし、あなたは慎重に検討してくださいする必要があります。

  • rsync(理想的と別のものに1つのディレクトリの内容をマージすることができます--remove-source-files1つの安全に正常に転送されたもののみソースファイルを削除するオプション、および通常の許可/所有/時間の保存オプションを使用して-a必要であれば)
    ... しかし、これは完全なコピー操作であります、したがって、非常にディスクを集中的に使用できます。
  • 現在推奨されているオプション:rsync--link-dest=DIRオプションを組み合わせて(可能な場合、ファイルの内容をコピーする代わりにハードリンクを作成する)--remove-source-files、通常のmv
    この--link-destためには、ソースディレクトリへの絶対パス(または宛先からソースへの相対パス)を指定する必要があります。
    ... しかし、これは--link-dest意図しない方法で使用され(複雑化の原因となる可能性はありません)、ソースへの絶対パスを(または決定して)知る必要があり--link-dest、再び空のディレクトリ構造を残してクリーンアップしますあたり1
  • を使用findして、ターゲットでソースディレクトリ構造を順番に再作成し、実際のファイルを個別に移動することができます
    ... しかし、これはソースを複数回再帰する必要があり、競合状態に遭遇する可能性があります(マルチステッププロセス中にソースで新しいディレクトリが作成されます) )
  • cpハードリンクを作成することができますマージと非常に類似した結果を作成します(同じ既存のファイルに簡単に言えば、追加のポインタ)、 mv(およびポインタのみが作成されているので非常にIO-効率的で、実際のデータをコピーする必要がありません)
    ... しかし、この再び競合状態が発生する可能性があります(ソースの新しいファイルは前の手順でコピーされていなくても削除されます)

これらの回避策(存在する場合)のどれが適切かは、特定のユースケースに大きく依存します。
いつものように、これらのコマンドを実行する前に考えて、バックアップを作成してください。


1:rsync --remove-source-filesディレクトリは削除されないことに注意してください。そのためfind -depth -type d -empty -delete、空のソースディレクトリツリーを削除するために、後ほど何かをする必要があります。


の実装を1つだけ試したようですmv。この答えは、より広い真実があればより良いでしょう。Linux、BSD、および「実際の」Unix、またはPOSIXまたはSUSからの参照。
ウォーレンヤング

@WarrenYoungそうだね、私が試しただけmvのDebianで使用される実装を-重点が上であることを試みた、manページがこの動作を言及していないので、...
n.st

38
rsyncの欠点は、ハードリンクを変更するだけでなく、実際にデータをコピーすることです。これは、大量のデータを処理している場合、リソースを大量に消費する可能性があります。
ジョナサンメイヤー

7
@Keithコピー元ディレクトリに存在しないコピー先ディレクトリの--deleteファイルのみを削除することに注意してください。
-n.st

1
@JonathanMayer rsync。いくつかのハードリンク関連機能として。たとえば、-H関数を使用してハードリンクを保持することも、宛先を使用してファイルをハードリンクすることもできます--link-dest。ただし、使用する前にマニュアルページを参照してください。
allo

87
rsync -av /source/ /destination/
(after checking)
rm -rf /source/

これにより、n.stのコメントのようにソースファイルが削除されますか?
ドミニク

3
いいえ、安全上の理由から2段階で作成したいと思います。マージおよび削除されたソースは元に戻せません。n.st anwerのAdditonステップも必要です(ディレクトリを削除するため)。
ファジー

3
--remove-source-files正常に転送されたファイルのみを削除するという利点があるfindため、空のディレクトリを削除するために使用でき、rsync出力を確認せずに転送されなかったすべてのものが残されます。
n.st

4
しかし、実際には動いていません。大きなファイルが関係する場合、速度への影響は非常に大きくなります。
アレックス

ただし、実際に純粋な移動とマージを実行することはできません。
ファジー

64

cpコマンドの-lオプションを使用すると、完全なデータコピーの代わりに同じファイルシステムにファイルのハードリンクを作成できます。次のコマンドは、フォルダーを親フォルダー()にコピーします。親フォルダーには、という名前のディレクトリが既に含まれています。source/folderdestinationfolder

cp -rl source/folder destination
rm -r source/folder

必要に応じて、-P--no-dereference-シンボリックリンクを逆参照しない)または-a--archive-すべてのメタデータを保持し、-Pオプションも含む)を使用することもできます。


7
@rautamiekka:ハードリンクを使用する理由を尋ねていると思います。ハードリンクとは何か、なぜそれらを使用する必要があるのか​​わからない場合は、おそらくこのルートを使用しないでください。ただし、ハードリンクを作成しても完全なコピーは行われないため、この操作にかかる時間は完全なコピーよりも桁違いに短くなります。また、ソースファイルを削除し、無効なパスへのポインターの代わりに正しいデータを保持できるように、ソフトリンクではなくハードリンクを使用します。そして、cpいうよりrsync、すべてのシステムが持っているのでcp、誰もがそれに精通しています。
palswim

7
この解決策の素晴らしさは、受け入れられた答えではないために見落とされるかもしれません。これはエレガントなソリューションです。cpの操作時間でのマージ機能を取得しmvます。
TheHerk 16

2
あなたはすでにあなたにも追加したい先に存在するファイルを移動する必要がないことがわかっている場合-n
ndemou

1
@Ruslan:これは事実ですが、何らかの方法でファイルシステム間でコピーなしで移動することはできません。でもmv /fs1/file /fs2/(ファイルシステム全体)コピーを実行してから削除します。
palswim

2
正しいが、mv「ターゲットディレクトリがまだ存在しない場合」は動作しますが、「効率的に」またはあなたがそれを呼ぶものでcp -rlなくても失敗します。
ルスラン

23

次の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

引数

これは非常に便利に見えます。私は私のハードドライブをクリーンアップするためにそれを使用したいです。このスクリプトに多数のバックアップを委託する前に、他の専門家がコメントすることはできますか?:-)
LarsH

ところで、(少なくともrsync -u新しいmvバージョンの場合にのみ)同等の処理を行いたい場合は、(少なくとも一部のバージョンでは)-uオプションを使用することもできます。ただし、その場合は、ソースツリー内のファイルが新しくない場合に対応するために、空ではないソースディレクトリだけでなくソースディレクトリも削除する必要があります。@schuess:必要な場合、複数のSOURCE引数が存在するようです。
LarsH

1
これは空白をうまく処理しません。いくつかのディレクトリにスペースを入れて試してみたところ、入れ子になったディレクトリが無限に並んでしまいました。
ローファー

16

以下はディレクトリをマージする方法です。ファイルをコピーしてから削除するのではなく、ファイルの名前を変更するだけなので、rsyncよりもはるかに高速です。

cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'

これは興味深いが、トピックに漠然と関連しているだけであり、ユーザーが尋ねたものはリモートでもありません。
シャドゥール14

17
実際、Jewelのコードは、欠落しているディレクトリを作成することを除いて、ユーザーが要求したことを正確に実行します。おそらくあなたはもう一度見る必要がありますか?
ジョナサンメイヤー

3
名前にスペースが含まれるファイルがあるため、findで「-print0」を使用し、xargsで「-0」を使用します。また、名前に括弧が含まれている場合、それらは移動されないという小さな問題があります。
markuz

2
これは、少数のファイルではrsyncよりもはるかに高速ですが、すべてのファイルで新しいプロセスを分岐するため、多数の小さなファイルではパフォーマンスがひどくなります。@palswimの答えはこの問題の影響を受けません。
-b0fh

2
in destがin と同じ名前のディレクトリである場合、コマンドは失敗しsourceます。そして、ファイルはに移動さdestsourceます。コマンドは、mv source/* source/dest/.
ceving

3

これを達成する1つの方法は、以下を使用することです。

mv folder/* directory/folder/
rmdir folder

folderdirectory/folderで同じ名前のファイルが2つもない限り、同じ結果、つまりマージが行われます。


3
どのように正確に機能しrm folderますか?
JakeGould

5
@JakeGouldまったくありません。:)
n.st

rm folder -fR常に私のために働く
タコ

2
これは隠しファイルでは機能しないことに注意してください
-b0fh

2

最も純粋なコピーには、tar(-)Bブロック読み取りコピー方式を使用します。

たとえば、ソースパス内から(必要に応じて「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 / stdin

sourcefolderすることもできる*(現在のフォルダに何のために)


f -通常、tarの指定は不要です。デフォルトでは、stdin / writeからstdoutに読み取ります。
ムル

1

ここに私のために働いたスクリプトがあります。私は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

このソリューションはパス名を適切にエスケープしません。注意してください。
user12439

@ user12439、どの部分を修正するか教えていただければ解決策を更新します。
xer0x

1

cpやrsyncなどのコマンドを使用することはお勧めできません。大きなファイルの場合、時間がかかります。mvは、ファイルを物理的にコピーせずにiノードのみを更新するため、はるかに高速です。より良いオプションは、オペレーティングシステムのファイルマネージャを使用することです。OpenSuseには、Konquererというファイルマネージャーがあります。実際にコピーせずにファイルを移動できます。Windowsのような「カットアンドペースト」機能があります。ディレクトリAのすべてのサブディレクトリを選択します。右クリックして、同じ名前のサブディレクトリを含むディレクトリBに「移動」します。それらをマージします。同じ名前のファイルを上書きするか名前を変更するかを選択するオプションもあります。


1
OP mvは使用時に何が起こるかを尋ねます。
-don_crissti

0

Pythonソリューション

満足できる既存のソリューションを見つけることができなかったので、それを達成するために簡単なPythonスクリプトを作成することにしました。

特に、このメソッドはボトムアップでソースファイルツリーをたどるだけなので、効率的です。

また、ファイルの上書き処理などを好みに合わせてすばやく調整できます。

使用法:

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)

GitHubアップストリーム

参照:https : //stackoverflow.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command


0

これは、ファイルとフォルダーを他の宛先に移動するためのコマンドです。

$ mv /source/path/folder /target/destination/

注意mvフォルダーがb̲e̲i̲n̲g m̲e̲r̲ge̲d̲(つまり、同じ名前の別のフォルダーが既に宛先に存在する)および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 for directory(folder)
-f force execution

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.