Làm thế nào để loại bỏ tất cả các thư mục trống trong một cây con?


151

Làm thế nào tôi có thể loại bỏ tất cả các thư mục trống trong một cây con? Tôi đã sử dụng một cái gì đó như

find . -type d -exec rmdir {} 2>/dev/null \;

nhưng tôi cần được chạy nhiều lần để xóa các thư mục chỉ chứa các thư mục trống. Hơn nữa, nó khá chậm, đặc biệt là dưới cygwin.


Xem thêm emacs.stackexchange.com/q/12190/2264 để biết giải pháp emacs.
Sean Allred

Câu trả lời:


222

Kết hợp findcác tùy chọn và vị từ GNU , lệnh này sẽ thực hiện công việc:

find . -type d -empty -delete
  • -type d hạn chế vào thư mục
  • -empty hạn chế những cái trống
  • -delete xóa từng thư mục

Cây được đi từ lá mà không cần chỉ định -depthvì nó được ngụ ý bởi -delete.


2
-deleteđã ngụ ý -depthvì vậy bạn không cần chỉ định thủ công.
jamadagni

1
Cảm ơn, tôi đã không nhận ra điều đó. Trả lời cập nhật.
Barshe Drevet-Droguet

11
Tôi sẽ thêm -mindepth 1vào đây, để ngăn chặn việc xóa chính thư mục bắt đầu, nếu nó sẽ trống.
Greg Dubicki

2
Tuyệt vời, nhưng không hoạt động trên các máy chủ SunOS cũ của tôi ...
dokaspar

2
!có một ý nghĩa đặc biệt cho vỏ. Bạn cần phải thoát khỏi nó. Một cái gì đó như: \! -name 'Completed'chỉ trước khi -deletelàm việc. Hoặc bạn chỉ cần đặt một tập tin đánh dấu trong thư mục này.
Barshe Drevet-Droguet

53

Liệt kê các thư mục lồng nhau sâu trước.

find . -depth -type d -exec rmdir {} \; 2>/dev/null

(Lưu ý rằng chuyển hướng áp dụng cho findtoàn bộ lệnh, không chỉ cho rmdir. Chuyển hướng chỉ để rmdirgây ra sự chậm lại đáng kể vì bạn cần phải gọi một lớp vỏ trung gian.)

Bạn có thể tránh chạy rmdirtrên các thư mục không trống bằng cách chuyển -emptyvị ngữ cần tìm. GNU find kiểm tra thư mục khi nó sắp chạy lệnh, vì vậy các thư mục vừa bị xóa sẽ được chọn.

find . -depth -type d -empty -exec rmdir {} \;

Một cách khác để tăng tốc sẽ là nhóm các rmdiryêu cầu. Cả hai đều có khả năng nhanh hơn đáng kể so với bản gốc, đặc biệt là dưới Cygwin. Tôi không mong đợi nhiều sự khác biệt giữa hai điều này.

find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null

Phương pháp nào nhanh hơn phụ thuộc vào số lượng thư mục không trống của bạn. Bạn không thể kết hợp -emptyvới các phương pháp để nhóm các yêu cầu, bởi vì sau đó các thư mục chỉ chứa các thư mục trống sẽ không trống theo thời gian findnhìn vào chúng.

Một phương pháp khác là chạy nhiều lượt. Việc này có nhanh hơn hay không phụ thuộc vào rất nhiều thứ, bao gồm cả việc phân cấp toàn bộ thư mục có thể duy trì trong bộ đệm của đĩa giữa các findlần chạy hay không.

while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done

Ngoài ra, sử dụng zsh. Vòng loại toàn cầu F khớp với các thư mục không trống, do đó /^Fkhớp với các thư mục trống. Các thư mục chỉ chứa các thư mục trống không thể được so khớp dễ dàng.

while rmdir **/*(/N^F); do :; done

(Điều này chấm dứt khi rmdirnhận được một dòng lệnh trống.)


Đó là nó. Thay vì 90 giây, phải mất 0,90 giây.
maaartinus

@maaartinus: Tôi tò mò: bạn có bộ dữ liệu tương tự mà bạn có thể thử mà không cần không -p? Tôi sẽ không nghĩ rằng nó sẽ làm cho một sự khác biệt.
Gilles

3
@maartinus - tối ưu hóa nhỏ khác: thêm -emptynên hoạt động với cái này (mặc dù tôi không chắc chính xác nó sẽ kiếm được bao nhiêu). Và rất, rất tầm thường, vì có lẽ bạn không muốn xóa ., sử dụng -mindepth 1.
mattdm

Đó không phải là loại bỏ mà là quá trình bắt đầu, chi phí gần như mọi lúc. Tôi đã bỏ qua cuộc -depthtranh luận, mà làm cho rmdir -pvô dụng. Tôi đã thay đổi nhận xét của mình rồi. Những năm 90 là nỗ lực ban đầu của tôi; Không có gì đáng ngạc nhiên ở đây.
maaartinus

2
Tôi nhận ra rằng chúng ta có thể loại bỏ rmdirlệnh gọi hoàn toàn, ít nhất là với GNU find, với lệnh này:find . -depth -type d -empty -delete
Barshe Drevet-Droguet

6

Nếu bạn chỉ giải quyết -pvấn đề của mình rmdir, điều đó sẽ hoạt động trong một lần. Nó sẽ không đẹp hoặc tối ưu, nhưng nó sẽ có được mọi thứ. Điều đó nói với rmdir để xóa bất kỳ thư mục cha không trống nào của thư mục bạn đang xóa.

Bạn có thể tiết kiệm một chút bằng cách thêm -emptybài kiểm tra để tìm, vì vậy nó không bận tâm với các thư mục không trống.


3

find . -depth -type d -exec rmdir {} +

là câu trả lời đơn giản và chuẩn nhất cho câu hỏi này.

Thật không may, tất cả các câu trả lời khác được đưa ra ở đây đều phụ thuộc vào các cải tiến cụ thể của nhà cung cấp không tồn tại trên tất cả các hệ thống.


3
Câu trả lời này gây ra lỗi cho mỗi thư mục không thể xóa được, có thể ít hơn mong muốn.
Willem van Ketwich

0

find . -type d -printf "%d %p\n" |\ sort -nr |\ perl -pe 's/^\d+\s//;' |\ while read dir; do \ (rmdir "$dir" > /dev/null 2>&1); \ done

Đây là cách nó hoạt động:

  1. Danh sách đệ quy tất cả các thư mục cùng với độ sâu của chúng
  2. Sắp xếp theo thứ tự giảm dần độ sâu của chúng
  3. Chỉ lọc các đường dẫn thư mục
  4. Chạy rmdirtrong danh sách từng cái một

0

Tôi sử dụng các bí danh này cho findcác lệnh được sử dụng thường xuyên , đặc biệt là khi tôi dọn sạch không gian đĩa bằng dupeguru , trong đó việc loại bỏ các bản sao có thể dẫn đến rất nhiều thư mục trống.

Nhận xét bên trong .bashrcvì vậy tôi sẽ không quên chúng sau này khi tôi cần chỉnh nó.

# find empty directories
alias find-empty='find . -type d -empty'

# fine empty/zero sized files
alias find-zero='find . -type f -empty'

# delete all empty directories!
alias find-empty-delete='find-empty -delete'

# delete empty directories when `-delete` option is not available.
# output null character (instead of newline) as separator. used together
# with `xargs -0`, will handle filenames with spaces and special chars.
alias find-empty-delete2='find-empty -print0 | xargs -0 rmdir -p'

# alternative version using `-exec` with `+`, similar to xargs.
# {}: path of current file
# +: {} is replaced with as many pathnames as possible for each invocation.
alias find-empty-delete3='find-empty -exec rmdir -p {} +'

# for removing zero sized files, we can't de-dupe them automatically
# since they are technically all the same, so they are typically left
# beind. this removes them if needed.
alias  find-zero-delete='find-zero -delete'
alias find-zero-delete2='find-zero -print0 | xargs -0 rm'
alias find-zero-delete3='find-zero -exec rm {} +'

-2

rm -r */lệnh làm việc dễ dàng cho tôi. rmnên yêu cầu -floại bỏ mạnh mẽ các thư mục với các tập tin. rm -rchỉ nên loại bỏ các thư mục trống. Tôi cởi mở tại sao điều này có thể sai. Điều này cũng nên để lại các tập tin vì */chỉ nhìn vào các thư mục.


1
Trước tiên, tôi khuyên bạn nên kiểm tra kỹ lưỡng vì rmchủ yếu là xóa các tệp. Mặc dù */chỉ phù hợp với các thư mục, tôi không biết nó làm gì ở cấp độ sâu hơn. Tôi cũng có thể tưởng tượng rằng nó chỉ hoạt động trên một số hệ thống.
maaartinus
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.