TL; DR: cách tốt nhất là sử dụng -exec rm
thay vì -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Giải trình:
Tại sao tìm thấy phàn nàn khi bạn cố gắng sử dụng -delete
với -prune
?
Câu trả lời ngắn: bởi vì -delete
ngụ ý -depth
và -depth
làm cho -prune
không hiệu quả.
Trước khi chúng ta đi đến câu trả lời dài, trước tiên hãy quan sát hành vi tìm và không có -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Không có gì đảm bảo về thứ tự trong một thư mục. Nhưng có một đảm bảo rằng một thư mục được xử lý trước nội dung của nó. Lưu ý foo/
trước bất kỳ foo/*
và foo/bar
trước bất kỳ foo/bar/*
.
Điều này có thể được đảo ngược với -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Lưu ý rằng bây giờ tất cả foo/*
xuất hiện trước foo/
. Tương tự với foo/bar
.
Câu trả lời dài hơn:
-prune
ngăn chặn tìm thấy từ giảm dần vào một thư mục. Nói cách khác -prune
bỏ qua nội dung của thư mục. Trong trường hợp của bạn -name b -prune
ngăn không cho tìm thấy giảm dần vào bất kỳ thư mục có tên b
.
-depth
tìm để xử lý nội dung của một thư mục trước chính thư mục đó. Điều đó có nghĩa là theo thời gian tìm được để xử lý mục nhập thư mục b
nội dung của nó đã được xử lý. Do đó -prune
là không hiệu quả với có -depth
hiệu lực.
-delete
ngụ ý -depth
để nó có thể xóa các tập tin đầu tiên và sau đó là thư mục trống. -delete
từ chối xóa các thư mục không trống. Tôi đoán có thể thêm một tùy chọn để buộc -delete
xóa các thư mục không trống và / hoặc để ngăn chặn -delete
ngụ ý -depth
. Nhưng đó là một câu truyện khác.
Có một cách khác để đạt được những gì bạn muốn:
find a -not -path "*/b*" -type f -delete
Điều này có thể hoặc có thể không dễ nhớ hơn.
Lệnh này vẫn đi vào thư mục b
và xử lý mọi tệp duy nhất trong đó chỉ -not
để từ chối chúng. Đây có thể là một vấn đề hiệu suất nếu thư mục b
rất lớn.
-path
hoạt động khác hơn -name
. -name
chỉ khớp với tên (của tệp hoặc thư mục) trong khi -path
khớp với toàn bộ đường dẫn. Ví dụ quan sát đường dẫn /home/lesmana/foo/bar
. -name -bar
sẽ phù hợp vì tên là bar
. -path "*/foo*"
sẽ khớp bởi vì chuỗi /foo
nằm trong đường dẫn. -path
có một số điều phức tạp bạn nên hiểu trước khi sử dụng nó. Đọc trang người đàn ông find
để biết thêm chi tiết.
Coi chừng rằng điều này không phải là 100%. Có nhiều khả năng "dương tính giả". Cách lệnh được viết ở trên nó sẽ bỏ qua bất kỳ tệp nào có bất kỳ thư mục mẹ nào có tên bắt đầu bằng b
(positive). Nhưng nó cũng sẽ bỏ qua bất kỳ tập tin nào tên bắt đầu với b
bất kể vị trí trong cây (dương tính giả). Điều này có thể được sửa chữa bằng cách viết một biểu thức tốt hơn "*/b*"
. Điều đó được để lại như một bài tập cho người đọc.
Tôi giả sử rằng bạn đã sử dụng a
và b
là người giữ chỗ và tên thật giống allosaurus
và hơn brachiosaurus
. Nếu bạn brachiosaurus
thay thế b
thì số lượng dương tính giả sẽ giảm đáng kể.
Ít nhất là các dương tính giả sẽ không bị xóa, vì vậy nó sẽ không bi thảm như vậy. Hơn nữa, bạn có thể kiểm tra dương tính giả bằng cách trước tiên chạy lệnh mà không -delete
(nhưng nhớ đặt hàm ý -depth
) và kiểm tra đầu ra.
find a -not -path "*/b*" -type f -depth
a
ngoại trừa/b
?