web-dev-qa-db-ja.com

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

mvを使用して「folder」という名前のフォルダを、すでに「folder」が含まれているディレクトリに移動すると、それらはマージされるか、それとも置き換えられますか?

157
Dominique

mvはディレクトリをマージまたは上書きできません。メッセージ "mv:cannot a move a 'b':Directory not empty"を使用していても失敗します。 --forceオプション。


他のツール(rsyncfind、またはcpなど)を使用してこれを回避できますが、その影響を慎重に検討する必要があります。

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

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


1:rsync --remove-source-filesはディレクトリを削除しないことに注意してください。空のソースディレクトリツリーを削除するには、後でfind -depth -type d -empty -deleteのような処理を行う必要があります。

127
n.st
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
90
fazie

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

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

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

68
palswim

次の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
23
Jonathan Mayer

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

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

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

mv folder/* directory/folder/
rmdir folder

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

4
asheeshr

最も純粋なコピーの場合、私は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/stdin

sourcefolder*にすることもできます(現在のフォルダー内のすべてのもの)

4
gjs

これは私のために働いたスクリプトです。私は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
1
xer0x

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

1
simon

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)

GitHubアップストリーム

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

空のフォルダをコピーする意味がない-YMMV

#!/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
  • 複数回実行されていないことがわかります
  • mkdir -pは、ディレクトリを順次検索した後でも実行されます

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

$ 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強制実行

0
Talha Siddiqi

abを次のようにマージできます:

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を使用して、空のディレクトリを削除します。

0
sir__finley