TL; DR:
Tất cả các tệp có trong cả hai srcvà destcó thể được xóa khỏi destnhư thế này:
find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;
Để biết từng bước, giải thích, xem bên dưới.
Đơn giản hóa vấn đề:
Để hiểu lệnh mà chúng ta muốn hoàn tác thực sự đã làm gì, chúng ta bắt đầu bằng cách mô phỏng nó:
Lệnh chúng tôi muốn hoàn tác là
sudo cp From_SOURCE/* To_DESTINATION/
Để hiểu cách hoàn tác, sudo không liên quan.
Tôi sẽ sử dụng tên thư srcmục cho From_SOURCEvà destcho To_DESTINATION.
Bây giờ, lệnh của chúng tôi là:
cp src/* dest/
Nếu srcchứa các tệp f1, f2và f3, và các thư mục d1và d2, shell sẽ mở rộng lệnh đó thành:
cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/
Không có các tùy chọn như -r, -Rhoặc -a, lệnh cpkhông sao chép các thư mục.
Điều đó có nghĩa là, lệnh sẽ loại bỏ chúng, hiển thị một lỗi cho mỗi trong số chúng:
$ cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/
cp: omitting directory 'src/d1'
cp: omitting directory 'src/d2'
Điều đó có nghĩa là, chúng tôi chỉ sao chép các tệp đơn giản và không có thư mục nào dest.
Quyết định loại bỏ các tập tin:
Có thể có các tệp destcó cùng tên với các tệp trongsrc . Trong trường hợp này, các tập tin đã bị ghi đè (1). Xin lỗi, quá muộn cho họ. Nhận chúng trở lại từ bản sao lưu mới nhất.
Về các tệp đang ở đó, chúng tôi muốn xóa chỉ các tệp đã được sao chép. Các tệp này tồn tại trong cả hai thư mục, có cùng tên và cùng một nội dung.
Vì vậy, chúng tôi tìm kiếm các tập tin này:
Đầu tiên, chúng ta cdvào src, bởi vì nó làm cho các findlệnh sau đơn giản hơn nhiều và đặt một biến thành đường dẫn tuyệt đối của mệnh:
$ cd src
$ destdir="$(readlink -f dest)"
Sau đó, chúng tôi liệt kê tất cả các tệp trong src:
$ find . -maxdepth 1 -type f
và, đối với mỗi tệp được tìm thấy, hãy sử dụng cmpđể kiểm tra xem có tệp nào có cùng nội dung trong mệnh hay không:
$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -print
Xóa các tập tin, cẩn thận:
Những tập tin này là những cái chúng tôi muốn loại bỏ. Nhưng để chắc chắn, trước tiên chúng ta di chuyển chúng vào một thư mục khác - và xem qua các lệnh trước khi chạy chúng:
$ 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/`
Có vẻ tốt! Bây giờ chúng ta có thể bỏ qua echođể chạy các mvlệnh thực sự :
find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;
Tất cả các tệp từ destđó đã được sao chép từ srcvà vẫn thực sự giống nhau srcvà desthiện đang ở trong /tmp/toDelete/và có thể được xóa sau khi xem qua.
Lưu ý:
(1) Kiểm tra xem có phải cplà bí danh cp -ihay không, điều đó có ngăn được các tập tin ghi đè bằng cách hỏi trước không.