TL; DR:
Tất cả các tệp có trong cả hai src
và dest
có thể được xóa khỏi dest
như 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ư src
mục cho From_SOURCE
và dest
cho To_DESTINATION
.
Bây giờ, lệnh của chúng tôi là:
cp src/* dest/
Nếu src
chứa các tệp f1
, f2
và f3
, và các thư mục d1
và 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
, -R
hoặc -a
, lệnh cp
khô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 dest
có 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 cd
vào src
, bởi vì nó làm cho các find
lệ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 mv
lệ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ừ src
và vẫn thực sự giống nhau src
và dest
hiệ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 cp
là bí danh cp -i
hay không, điều đó có ngăn được các tập tin ghi đè bằng cách hỏi trước không.