Batalkan salin (cp) tindakan perintah

14

Saya menyalin beberapa file dari folder sumber ke folder tujuan dengan menggunakan perintah di bawah ini di terminal.

sudo cp From_SOURCE/* To_DESTINATION/

Sekarang saya ingin membatalkan perintah ini.

αғsнιη
sumber
Saya tidak yakin saya mengerti. Cukup hapus salinannya? (sudo rm file)
Jacob Vlijm
@ JacobVlijm itu bukan membatalkan tindakan itu adalah perintah yang terpisah. Jika saya tidak menyalin sehingga saya bisa menggunakan perintah yang Anda sarankan sebelumnya. Dan saya harus semakin banyak menggunakan perintah ini untuk menghapus lebih dari 1000 file yang disalin?
αғsнιη
@KasiyA - sebuah opsi adalah menemukan semua nama file yang dipilih From_SOURCE/*, dan menghapusnya dari To_DESTINATION/; ini bisa dilakukan dengan bash - masalah di sini dapat mencakup perintah cp menimpa apa pun, symlink disalin, file dengan spasi dalam nama, dll - sehingga bisa memiliki masalah dan agak aneh. Opsi 'undo' yang sempurna mungkin harus memperhitungkan banyak hal.
Wilf

Jawaban:

13

Jika saya mengerti dengan baik, berikut ini kasusnya:

  • Anda menyalin sejumlah (mungkin besar) file ke direktori yang ada, dan Anda perlu / ingin membalikkan tindakan.
  • Direktori yang ditargetkan berisi sejumlah file lain , yang perlu Anda simpan di sana, yang membuatnya tidak mungkin menghapus semua file dari direktori

Skrip di bawah ini terlihat di direktori (sumber) asli dan mencantumkan file-file itu. Kemudian ia melihat ke direktori tempat Anda menyalin file, dan hanya menghapus file yang terdaftar, seperti yang ada di direktori sumber.

The tryelemen ditambahkan untuk mencegah kesalahan, misalnya dalam kasus Anda mungkin telah menghapus beberapa file secara manual sudah, atau jika tidak semua file dari direktori sumber disalin ke tujuan. Jika Anda membutuhkan hak sudo, cukup jalankan skrip dengan "sudo" (lihat di bawah).

Naskah

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for root, dirs, files in os.walk(source_dir):
    for name in files:
        try:
            os.remove(target_folder+"/"+name)
        except FileNotFoundError:
            pass

Cara Penggunaan

  • Rekatkan skrip ke dalam file kosong, simpan sebagai reverse.py,
  • Masukkan jalur yang benar untuk folder sumber dan target,
  • Jadikan itu dapat dieksekusi untuk alasan kenyamanan,
  • Jalankan dengan perintah:

    [sudo] /path/to/reverse.py
    

Peringatan

Pertama coba di direktori tes jika saya mengerti dengan baik apa yang perlu Anda capai!


Jika direktori sumbernya adalah "flat"

Jika direktori sumber tidak memiliki sub-direktori, skrip bahkan dapat lebih sederhana:

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for file in os.listdir(source_dir):
    try:
        os.remove(target_folder+"/"+file)
    except FileNotFoundError:
        pass

Catatan

Jika tindakan salin menimpa (diganti) file dengan nama yang sama di tujuan, file tersebut akan dihapus, tetapi file asli tidak akan dikembalikan oleh skrip. Asumsinya adalah tidak ada bentrokan nama.

Yakub Vlijm
sumber
Berhasil, terima kasih. Saya menjalankannya sudo python3 reverse.py. Saya menerima jawaban Anda.
αғsнιη
Sempurna! Terima kasih atas pertanyaan yang bagus, yang menggambarkan situasi yang mungkin kita alami semua :)
Jacob Vlijm
Catatan: Jika ada file di sumber yang menimpa file di tujuan karena memiliki nama yang sama, maka Anda tidak bisa begitu saja membatalkannya, dan skrip ini hanya akan menghapusnya. Asumsinya di sini adalah tidak ada bentrokan nama saat Anda melakukan inisial cp.
thomasrutter
@neon_overload Benar, diedit dalam jawaban saya.
Jacob Vlijm
Ini tidak berhasil cp -r. Saya berubah os.removedengan print, dan itu menghasilkan banyak file yang tidak ada. Saya menganggap itu hilang subdirektori, dan hanya daftar file di akhir.
Typewar
7

TL; DR:

Semua file yang ada di keduanya srcdan destdapat dihapus dari destseperti ini:

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Untuk langkah demi langkah, penjelasan, lihat di bawah.

Menyederhanakan masalah:

Untuk memahami apa yang sebenarnya ingin kami batalkan, kami mulai dengan menyederhanakannya:

Perintah yang ingin kita batalkan adalah

sudo cp From_SOURCE/* To_DESTINATION/

Untuk memahami cara membatalkan, sudo tidak relevan.

Saya akan menggunakan nama direktori srcuntuk From_SOURCEdan destuntukTo_DESTINATION .

Sekarang, perintah kami adalah:

cp src/* dest/

Jika srcberisi file f1, f2dan f3, dan direktori d1dan d2, shell memperluas perintah itu ke:

cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/

Tanpa opsi seperti -r, -Ratau -a, perintah cptidak menyalin direktori.
Itu berarti, perintah akan membiarkan mereka keluar, menunjukkan kesalahan untuk masing-masing dari mereka:

$ cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/
cp: omitting directory 'src/d1'
cp: omitting directory 'src/d2'

Itu berarti, kami hanya menyalin file sederhana, dan tidak ada direktori, ke dest.

Memutuskan file mana yang akan dihapus:

Mungkin ada file destdengan nama yang sama dengan file dalam src. Dalam hal ini, file-file tersebut ditimpa (1). Sudah terlambat bagi mereka, maaf. Dapatkan mereka kembali dari cadangan terbaru.

Mengenai file yang ada di sana, kami hanya ingin menghapus file yang sudah disalin. File-file ini ada di kedua direktori, dengan nama yang sama, dan konten yang sama.

Jadi kami mencari file-file ini:

Pertama, kita cdmasuk src, karena itu membuat findperintah berikut lebih sederhana, dan menetapkan variabel ke jalur absolut dest:

$ cd src
$ destdir="$(readlink -f dest)"

Lalu, kami daftar semua file di src:

$ find . -maxdepth 1 -type f

dan, untuk setiap file yang ditemukan, gunakan cmpuntuk memeriksa apakah ada file dengan konten yang sama di dest:

$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -print

Menghapus file, dengan hati-hati:

File-file ini adalah yang ingin kita hapus. Namun yang pasti, kami memindahkannya ke direktori yang berbeda terlebih dahulu - dan perhatikan perintah sebelum menjalankannya:

$ toDelete=/tmp/toDelete ; mkdir -p "$toDelete"
$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec echo mv -n "$destdir/{}" "$toDelete"/ \;
mv -n /path/to/dest/./f1 /tmp/toDelete/`
mv -n /path/to/dest/./f2 /tmp/toDelete/`
mv -n /path/to/dest/./f3 /tmp/toDelete/`

Kelihatan bagus! Sekarang kita bisa membiarkan echountuk menjalankan mvperintah nyata :

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Semua file dari destyang disalin dari src, dan masih benar-benar sama srcdan dest, sekarang /tmp/toDelete/, dan dapat dihapus setelah melihat terakhir.


Catatan:
(1) Periksa apakah cpalias cp -iatau lebih, yang akan mencegah menimpa file dengan bertanya terlebih dahulu.

Volker Siegel
sumber
5

Ini sudah tua, tetapi saya hanya ingin memposting jawaban bash murni:

Pertama, ubah ke direktori tempat Anda menyalin file.

cd dest

Lalu, lsdirektori sumber dan pipa output kerm

ls source | xargs rm

Michael Goldstein
sumber
1
parsing lsbiasanya ide yang buruk. mywiki.wooledge.org/ParsingLs Saya tidak akan mengunggah posting Anda, tetapi harus dicatat.
Sergiy Kolodyazhnyy