ターゲットファイルをmvで上書きする方法は?


155

親ディレクトリに移動したいサブディレクトリに大量のファイルとディレクトリがあります。ターゲットディレクトリには、上書きする必要のあるファイルとディレクトリが既にあります。ターゲットにのみ存在するファイルは変更しないでください。それを強制mvすることはできますか?それ(mv * ..)文句を言う

mv: cannot move `xyz' to `../xyz': Directory not empty

私は何が欠けていますか?


3
試しましたmv -fか?
サヤスク

なぜmv -f正解ではないのだろうか。
ペドロロビト

@PedroLobito:動作しないのですか?-fはファイルのみを上書きしますが、宛先に存在し空でないサブディレクトリを移動する場合は機能しません。
EricSchaefer

回答:


118

あなたは、コマンド使用して、先にコピーして、ソースを削除する必要がありますcp -r * ..が続きをrm -rf *

を使用してディレクトリを「マージ」できるとは思わないmv


4
まあ、それは私がやりたくなかったものです、時間がかかるので...とにかくありがとう。
EricSchaefer

12
mv同じファイルシステムを使用しているため、おそらく高速ですか?cp -l実際にファイルを移動するのではなく、ハードリンクの作成に使用するとどうなりますか?
mattdm

6
ファイル属性(タイムスタンプ、権限など)を保持するために、cp -a代わりに使用する必要がcp -rあります。
dotancohen

3
グーグル経由で遅れてここに到着した人のために、@ palswimによる以下の回答は、データへの新しいハードリンクを作成し、古いリンクを削除することにより、mvの動作をエミュレートします。短い答えcp -rl source destination && rm -r source
ウィリアムエベレット

72

rsyncここでおそらくより良いオプションでしょう。と同じくらい簡単rsync -a subdir/ ./です。

私のテストツリーfilename::contents形式:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

実行中rsync

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

与える:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

次に、エミュレートするにはmv、おそらくソースディレクトリを削除する必要があります。

$ rm -r subdir/

与える:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir

これが間違っている場合、希望する結果を備えた同様の例を提供できますか(たとえば、この回答の上部近くからテストツリーを使用して)。


1
rsyncコピー。この質問は移動についてです。
ジル

1
@Gilles:ありがとう。rm -r最後に追加して基本的に同じにしましたmv
ミケル

3
ソースと宛先が同じファイルシステム上にある場合、copy-then-deleteはmvと同等ではありません。mvアトミックで、inode番号を保持するため(ファイルを開いたままにすることができます)、コピーを作成するのに時間とスペースを必要としません。
ジル

5
@Gilles:それは理解していますが、現在の主な答えはcp -r; rm -rです。その意味で、rsync言及する価値があると思います。
ミケル

私はすでにcp / rmでそれをしました(緊急でした)。本当に長い時間がかかりました。ジルのスクリプトの方がおそらくずっと速かったでしょうが、彼も遅すぎました。
EricSchaefer

47

rsync--remove-source-filesパラメータを使用してコピー後にソースを削除できます。これは、あなたが望むことをする便利な方法であるはずです。

からrsync man page

        --remove-source-files   sender removes synchronized files (non-dir)

これは本当に最高の答えです。cp -r; rm空き容量がないため使用できませんでした。代わりにrsync --remove-source-files、使用済みのディスク領域を最小限に抑えたため、まったく同じファイルをコピーすることを避けました。
グアカ14

20

cpand rmでこれを行うことができますが、大量のデータをコピーすることなく、(おそらく)転送を避けようとしています。@mattdmは彼のコメントでこれをほのめかし、別の質問への回答にはさまざまなオプションに関するより完全な議論があります。

cp -rlf source destination
rm -r source

基本的に、コマンドの-lオプションは、cpデータを新しいファイルにコピーするのではなく、ファイルへのハードリンクを作成します。


1
OPが質問を促すタスクすでに完了していることは知っていますが、この回答が将来この問題を抱えている人の助けになることを願っています。
palswim

これが本当に必要な答えです。60GBの小さなサイラスメールファイルでこれを行ったところ、わずか21秒で完了しました。
ラブラドール

これは私が取ったルートでもありcp -al source destinationます。所有者の情報と権限を保持するために変更しました。
piit79

OPが-fオプションを追加する必要があることを要求したことを実際に実行すると、ファイルが存在する場合は上書きされません。それを確認できますか、何か間違っていますか?
ダスのKEK

@dasKeks:実際には、cpデフォルトで上書きします。この-fオプションは、rm新しくコピーしようとする前にファイルを削除しようとします(これは、プロセスが書き込み用にファイルを開けない場合に役立ちますが、代わりにエラーが発生したことを確認したい人もいます)。OPにとって重要かどうかはわかりませんが、-fとにかく答えにフラグを追加しました。
palswim

8

以下に、ファイルを下/path/to/source/rootから対応するパスに移動するスクリプトを示します/path/to/destination/root

  • ソースと宛先の両方にディレクトリが存在する場合、コンテンツは再帰的に移動およびマージされます。
  • ファイルまたはディレクトリがソースには存在するが、デスティネーションには存在しない場合、それらは移動されます。
  • 宛先にすでに存在するファイルまたはディレクトリはすべて残されます。(特に、マージされたディレクトリはソースに残されます。これは簡単に修正できません。)

未テストのコードに注意してください。

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d \( -exec sh -c '[ -d "$dest/$0" ]' \; -o \
                  -exec sh -c 'mv "$0" "$dest/$0"' {} \; -prune \) \
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0"
        fi
' {} \;

二つの訂正:あなたが必要とする\;-oの最初の行にfindコマンドを、そしてあなたが脱出はならない!if-それだけだ!、ではない\!
llhuii

2

このスレッドは何年もそこにあり、まだグーグルで1位にランクされているので、別のメソッドを追加したいと思いました。通常の方法:subdirコンテンツをtarballにパックし、tarballを親ディレクトリに移動してから、デフォルトの--overwrite動作で抽出します。これはまさにあなたが探しているものです。その後、サブディレクトリを削除できます。

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz

これは、圧縮tarファイル用の追加スペースがある場合にのみ機能します。そして、抽出後、一時的なtarファイルを本当に保持しますか?
アントン

tmpファイルを削除するためのコードを編集しました。現在、ほとんどの場合、スペースは問題ではありません。#terabyteages
サイモンクラウス

0

十分なストレージがある場合は、次の方法で実行できます。

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

末尾に〜が付いている重要なファイルがないことを確認しますが、ある場合--suffix=whateveryouwantはデフォルトの代わりに追加できます。

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