Bagaimana cara menimpa file target dengan mv?


155

Saya punya banyak file dan direktori dalam subdirektori yang ingin saya pindahkan ke direktori induk. Sudah ada beberapa file dan direktori di direktori target yang perlu ditimpa. File yang hanya ada di target harus dibiarkan tidak tersentuh. Bisakah saya memaksakan mvuntuk melakukan itu? Itu ( mv * ..) mengeluh

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

Apa yang saya lewatkan?


3
Sudahkah Anda mencoba mv -f?
sakisk

Saya bertanya-tanya mengapa mv -fjawaban itu tidak benar.
Pedro Lobito

@PedroLobito: Karena tidak berfungsi? -f hanya menimpa file, tetapi tidak berfungsi jika Anda memindahkan subdirektori yang ada di tujuan dan tidak kosong.
EricSchaefer

Jawaban:


118

Anda harus menyalinnya ke tujuan dan kemudian menghapus sumbernya, menggunakan perintah yang cp -r * ..diikuti oleh rm -rf *.

Saya tidak berpikir Anda dapat "menggabungkan" direktori menggunakan mv.


4
Yah, itu yang tidak ingin saya lakukan, karena itu akan memakan waktu lama ... Terima kasih.
EricSchaefer

12
Agaknya mvlebih cepat karena Anda berada di sistem file yang sama? Bagaimana jika Anda menggunakan cp -luntuk membuat hardlink daripada benar-benar memindahkan file?
mattdm

6
Anda harus menggunakan cp -aalih-alih cp -runtuk mempertahankan atribut file (cap waktu, izin, dll.).
dotancohen

3
Bagi orang-orang yang datang terlambat ke sini melalui google, jawaban di bawah ini oleh @palswim mengemulasi perilaku mv dengan membuat tautan keras baru ke data dan kemudian menghapus tautan lama. Jawaban singkat cp -rl source destination && rm -r source.
William Everett

72

rsyncmungkin akan menjadi pilihan yang lebih baik di sini. Sesederhana itu rsync -a subdir/ ./.

Pohon tes saya dalam filename: contentsformat:

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

Berlari rsync:

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

Memberi:

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

Dan kemudian, untuk meniru mv, Anda mungkin ingin menghapus direktori sumber:

$ rm -r subdir/

Memberi:

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

Jika ini salah, dapatkah Anda memberikan contoh serupa (mis. Menggunakan pohon pengujian saya dari dekat bagian atas jawaban ini) dengan hasil yang diinginkan?


1
salinan rsync. Pertanyaan ini tentang pindah.
Gilles

1
@Gilles: Terima kasih. Saya menambahkan rm -rpada akhirnya untuk membuatnya pada dasarnya sama dengan mv.
Mikel

3
copy-then-delete tidak setara dengan mv ketika sumber dan tujuan berada pada sistem file yang sama. mvbersifat atomik, mempertahankan nomor inode (agar file dapat tetap terbuka), dan tidak memerlukan waktu dan ruang untuk membuat salinan.
Gilles

5
@Gilles: Saya menyadari itu, tetapi saat ini jawabannya adalah cp -r; rm -r. Saya pikir dalam pengertian itu, rsynclayak disebut juga.
Mikel

Saya sudah melakukannya dengan cp / rm (sangat mendesak). Butuh waktu lama. Naskah Gilles mungkin akan jauh lebih cepat, tetapi dia sudah terlambat juga.
EricSchaefer

47

rsyncdapat menghapus sumber setelah salinan dengan --remove-source-filesparameter. Ini harus menjadi cara yang nyaman untuk melakukan apa yang Anda inginkan.

Dari rsync man page:

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

Ini benar-benar jawaban terbaik. Saya tidak dapat menggunakan cp -r; rmkarena kurangnya ruang kosong. Alih-alih rsync --remove-source-fileskedua ruang disk yang diperkecil dihindari menghindari menyalin file yang sama persis.
guaka

20

Anda dapat melakukan ini dengan cpdan rm, tetapi tanpa menyalin sejumlah besar data Anda (mungkin) berusaha menghindari transfer. @mattdm menyinggung ini dalam komentarnya , dan jawaban untuk pertanyaan lain memiliki diskusi yang lebih lengkap tentang berbagai opsi.

cp -rlf source destination
rm -r source

Pada dasarnya, -lopsi untuk cpperintah ini menciptakan tautan keras ke file daripada menyalin data mereka ke file baru.


1
Saya tahu OP sudah menyelesaikan tugasnya yang memicu pertanyaan, tapi mudah-mudahan jawaban ini dapat membantu siapa pun dengan masalah ini di masa depan.
palswim

Ini benar-benar jawaban yang mereka butuhkan. Saya hanya melakukan ini dengan 60GB ribuan file email cyrus kecil dan hanya butuh 21 detik.
labradort

Ini juga rute yang saya ambil - Saya baru saja mengubahnya cp -al source destinationuntuk menjaga info dan izin pemilik.
piit79

Saya pikir untuk benar-benar melakukan apa yang diminta OP untuk Anda harus menambahkan opsi -f jika tidak akan menimpa jika file ada. Bisakah Anda mengkonfirmasi itu atau saya melakukan sesuatu yang salah?
das Keks

@dasKeks: Sebenarnya, cpmenimpa secara default. The -fpilihan mencoba untuk menghapus file (seperti dalam rm) sebelum mencoba untuk menyalin lagi, yang dapat membantu jika proses tidak dapat membuka file untuk menulis, meskipun beberapa orang akan lebih memilih untuk melihat bahwa ada kesalahan sebagai gantinya. Saya tidak tahu apakah itu penting bagi OP, tetapi saya tetap menambahkan -fbendera pada jawaban saya.
palswim

8

Berikut ini skrip yang memindahkan file dari bawah /path/to/source/rootke jalur yang sesuai di bawah /path/to/destination/root.

  • Jika ada direktori di sumber dan tujuan, konten dipindahkan dan digabungkan secara rekursif.
  • Jika file atau direktori ada di sumber tetapi tidak di tujuan, itu dipindahkan.
  • File atau direktori apa pun yang sudah ada di tujuan tertinggal. (Khususnya, direktori gabungan tertinggal di sumbernya. Ini tidak mudah untuk diperbaiki.)

Hati-hati, kode yang belum diuji.

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
' {} \;

Dua koreksi: Anda perlu \;sebelum -odi baris pertama dari findperintah, dan Anda tidak harus melarikan diri !di if- itu hanya !, tidak\!
llhuii

2

Utas ini sudah ada selama bertahun-tahun dan masih menempati peringkat # 1 di google jadi saya ingin menambahkan metode lain. Bagaimana saya biasanya melakukan ini: mengemas konten subdir ke dalam tarball, memindahkan tarball ke direktori induk dan kemudian mengekstraknya dengan perilaku default --overwrite. Ini tepat seperti yang Anda cari. Setelah itu, Anda dapat menghapus subdir.

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

Ini hanya berfungsi jika Anda memiliki ruang ekstra untuk file tar terkompresi. Dan apakah Anda benar-benar ingin menyimpan file tar sementara setelah ekstraksi?
Anthon

Kode yang diedit untuk menghapus file tmp. Saat ini ruang tidak menjadi masalah dalam banyak kasus. #terabyteages
Simon Kraus

0

Jika Anda memiliki cukup penyimpanan, Anda dapat melakukannya dengan cara berikut:

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

Pastikan tidak ada file penting dengan tanda ~ di ujungnya, tetapi jika ada, Anda dapat menambahkan --suffix=whateveryouwantalih-alih default.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.