Làm thế nào để xóa các thư mục dựa trên đầu ra `find`?


148

Tôi đưa ra lệnh sau để tìm các thư mục .svn:

find . -name ".svn"

Điều đó cho tôi kết quả như sau:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Làm thế nào tôi có thể xử lý tất cả các dòng này rm -frđể xóa các thư mục và nội dung của chúng?


3
GNU find có -deletetùy chọn.
Marco

5
Hoặc bạn có thể thêm -exec rm -r "{}" \;vào cuối tìm kiếm - hãy cẩn thận khi sử dụng rm -r! :)
Drav Sloan

10
@Marco Tùy chọn xóa dường như không hoạt động trên các thư mục.
Arnaud

@SuperChafouin Nó hoạt động hoàn toàn tốt ở đây trên các tệp và thư mục. Vấn đề là nó chỉ xóa các thư mục emtpy và khi bạn chỉ định -name ".svn"nó chỉ khớp với .svnchính thư mục đó chứ không phải các tệp nằm trong .svnthư mục.
Marco

1
@SuperChafouin nhưng sẽ không hoạt động đối với các đường dẫn có khoảng trắng trong đó (do đó sử dụng -execvới trích dẫn "{}").
Drav Sloan

Câu trả lời:


194

Tìm có thể thực thi các đối số với -exectùy chọn cho mỗi trận đấu mà nó tìm thấy. Đây là một cơ chế được đề xuất vì bạn có thể xử lý các đường dẫn có dấu cách / dòng mới và các ký tự khác trong đó. Bạn sẽ phải xóa các nội dung của thư mục trước khi bạn có thể loại bỏ các thư mục riêng của mình, vì vậy sử dụng -rvới các rmlệnh để đạt được điều này.

Ví dụ của bạn, bạn có thể phát hành:

find . -name ".svn" -exec rm -r "{}" \;

Bạn cũng có thể yêu cầu tìm chỉ để tìm các thư mục có tên .svn bằng cách thêm một -type dkiểm tra:

find . -name ".svn" -type d -exec rm -r "{}" \;

Cảnh báo Sử dụng rm -rmột cách thận trọng, nó sẽ xóa thư mục và tất cả nội dung của nó.

Nếu bạn muốn xóa chỉ các thư mục trống cũng như các thư mục chỉ chứa các thư mục trống, find có thể tự làm điều đó với -delete-empty:

find . -name ".svn" -type d -empty -delete

22
Tôi đã thấy lời khuyên là luôn luôn chạy -type sau khi -name tìm lệnh, vì các lệnh gọi statđể lấy loại rất tốn kém. Tôi chỉ thử bản thân mình trên một tập tin khá lớn và có vẻ đúng: chạy find . -name 'foo' -type dmất 19 giây, trong khi find . -type d -name 'foo'mất 32 giây. Vì vậy, khoảng 50% thời gian dài hơn để chạy -typeđầu tiên.
spinup

6
Tôi đã sử dụng lệnh này trong nhiều năm, nhưng trên Mac bây giờ tôi gặp lỗi khi nói rằng các thư mục đó không tồn tại. Mặc dù nó sẽ xóa chúng. Tôi chưa bao giờ thấy tin nhắn trước đây.
chovy

1
Tương tự như @chovy. Có cách nào để thoát khỏi những tin nhắn này?
Clément

2
@chovy @ clément Đó là vì findmuốn xem trong thư mục đó cho các trận đấu khác, trong khi nó xóa thư mục cùng một lúc. ~ Tôi chưa biết cách khắc phục. ~ Sửa lỗi bẩn thỉu:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie

5
@chovy @ Clément Tôi nghĩ rằng -depthđối số đã khắc phục điều này:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland

67

Đây là một di động vẫn nhanh hơn cách trả lời được chấp nhận.

Sử dụng +thay vì dấu chấm phẩy làm dấu findkết thúc lệnh sẽ tối ưu hóa việc sử dụng CPU. Điều đó có thể có ý nghĩa nếu bạn có nhiều .svnthư mục con:

find . -name .svn -type d -exec rm -rf {} +

Cũng lưu ý rằng bạn không bao giờ 1 cần phải trích dẫn dấu ngoặc nhọn ở đây.

1 Trừ khi bạn sử dụng fishvỏ.


5
Sự khác biệt giữa dấu + và dấu chấm phẩy là gì? Tại sao chúng ta không sử dụng niềng răng xoăn?
Shicheng Guo

1
@ShichengGuo Với dấu chấm phẩy, sẽ có một lệnh rm cho mỗi thư mục được tìm thấy, với lệnh + một rm sẽ xử lý tất cả các thư mục được tìm thấy (hoặc ít nhất là một số lượng rất lớn trong số chúng.) Tôi không nhận được câu hỏi thứ hai, xoăn niềng răng được sử dụng ở đây.
jlliagre

Tôi nghĩ rằng @ShichengGuo có nghĩa là tại sao chúng ta không cần trích dẫn các dấu ngoặc nhọn ở đây (@jlliagre viết rằng chúng ta không bao giờ cần trích dẫn chúng). Bây giờ tôi không thể tìm thấy tài liệu tham khảo, nhưng tôi hiểu điều đó bởi vì find sẽ tự động thoát khỏi các đường dẫn được thay thế cho {}.
Quinn Comendant

Câu trả lời và câu hỏi không hoàn toàn đúng về những gì + làm. Nếu nhiều tệp được tìm thấy thì ';' sẽ đưa ra lỗi 'dòng lệnh quá dài'. + chia nhỏ các tệp được tìm thấy trong các lô nhỏ hơn độ dài dòng lệnh tối đa được phép và chạy lệnh cho mỗi lô.
gaoithe

1
@gaoithe Tôi đã chỉnh sửa lại bạn đã thay thế một câu lệnh đúng bằng một câu không đúng. Việc sử dụng + không làm giảm việc sử dụng CPU, Sử dụng ; không dẫn đến một lỗi quá dài lệnh.
jlliagre

27

Giả sử bạn đang sử dụng gnu find , bạn có thể sử dụng -deletetùy chọn:

find . -name test -delete

cái nào dễ nhớ hơn


Xem xét mở rộng bài đăng của bạn với một lời giải thích về lệnh (hoặc tài liệu để sao lưu giải pháp của bạn). Thường thì một (hoặc hai) câu trả lời không phải là câu trả lời rõ ràng nhất.
HalosGhost

94
Điều này không hoạt động trên các thư mục không trống.
belacqua

2
cũng hoạt động trên Mac OS X
vẽ

Điều này không hoạt động đối với thư mục không trống nhưng đó là giải pháp dễ dàng và an toàn hơn
RousseauAlexandre

Thứ tự tùy chọn là rất quan trọng, tìm sẽ thực hiện chúng theo thứ tự, vì vậy, phải là người cuối cùng
Jose Ignacio Centeno

13

Trên máy tính của tôi khi tôi sử dụng:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Các thư mục bị xóa nhưng tôi nhận được lỗi:

find: ‘./dirname’: No such file or directory

cho mỗi thư mục.

Thư mục của tôi không trống, vì vậy tùy chọn -delete sẽ không hoạt động với tôi. Tôi tìm thấy lý do cho hành vi này ở đây :

  1. find mất (không nhất thiết) mục đầu tiên trong thư mục ./. đây sẽ là ví dụ dir.1 /
  2. nó so sánh nó với mẫu 'dir.?'. nó có phù hợp không? Đúng.
  3. tìm thực thi "rm -r dir.1".
  4. find cố gắng nhập dir.1 / để tìm mẫu trong thư mục. nó không biết gì về lệnh exec.
  5. nó không tìm thấy dir.1 / nữa. trả về ENOENT (nhìn vào đầu ra strace)

Tôi đã sử dụng điều này thay vì để làm việc xung quanh:

rm -r `find . -name dirname -type d`

Hãy nhớ rằng find vẫn sẽ cố gắng truy xuất vào các thư mục có tên dirname, điều này không thực sự cần thiết và sẽ mất thêm thời gian. Tùy thuộc vào cấu trúc thư mục của bạn, bạn có thể giải quyết vấn đề này với --depthtùy chọn tìm. Ngoài ra, nếu bạn có cấu trúc thư mục như dirname / foo / dirname, bạn sẽ nhận được lỗi "Không có tệp hoặc thư mục như vậy" từ rm. Để loại bỏ lỗi, bạn có thể chuyển hướng stderr sang / dev / null hoặc sử dụng -fcờ (lực) với rm.


2
Ý tưởng tồi: tên tệp có dấu cách sẽ gây ra tất cả các loại vấn đề khủng khiếp
Clément

2
Dành cho những độc giả tương lai: find . -name "to-delete" -print0 | xargs -r0 -- rm -rlà phiên bản không thể khắc phục được, không bị rơi trên không gian
Charlie

3
Xem unix.stackexchange.com/a/115869/8257 bạn cần thêm -prune.
Mapio

1
Thêm -pruneđể tránh lỗi "Không có tệp hoặc thư mục như vậy".
Julien Carsique

12

Một cách nhanh hơn để làm điều này là:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Trong trường hợp bạn có ".svn" bên trong ".svn" khác.


Điều đó không hữu ích nếu bạn muốn tìm các thư mục cần xóa với các thư mục con.
Alexis Wilke

5

Giải pháp cụ thể của Bash:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion

3
Lưu ý đối với việc mở rộng dòng lệnh của các khối phù hợp với nhiều tệp, có giới hạn số lượng tệp bạn có thể khớp với cơ chế này. Vượt quá giới hạn này sẽ dẫn đếnbash: /bin/rm: Argument list too long
Drav Sloan

1
@DravSloan là chính xác, nhưng giới hạn đó nằm trong hàng trăm ngàn tệp. Đó là điều cần lưu ý, nhưng có lẽ sẽ không phải là vấn đề đối với hầu hết mọi người.
evilsoup

4

Tôi đã thấy rằng -deletehành động này hoạt động tốt với -paththử nghiệm. Chẳng hạn, những điều sau đây phải giải quyết vấn đề áp phích ban đầu:

find . -path '*/.svn*' -delete

Bạn có chắc không? -deletengụ ý -depthvà nó chắc chắn xóa các thư mục không trống trên hệ thống của tôi.
Magnus

Kiểm tra lại và nó hoạt động. Có lẽ đó chỉ là lỗi đánh máy mà tôi đã sửa.
kenorb

Tôi cũng đã thử cách tiếp cận này và nó đã hoạt động - các thư mục đã bị xóa.
Allan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.