Xóa tất cả các thư mục trong một thư mục ngoại trừ một thư mục có tên cụ thể


17

Tôi cần xóa tất cả các thư mục trong một thư mục bằng cách sử dụng tập lệnh hàng ngày. Thư mục cho ngày hôm đó cần phải được để lại.

Thư mục 'myfolder' có 3 thư mục con: 'test1', 'test2' và 'test3' Tôi cần xóa tất cả ngoại trừ 'test2'.

Tôi đang cố gắng để khớp tên chính xác ở đây:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

HOẶC LÀ

find /home/myfolder -type d ! -name 'test2' -delete

Lệnh này luôn cố gắng xóa thư mục chính 'myfolder'! Có cách nào để tránh điều này không ?


6
Trong Unix và Linux, chúng tôi gọi những "thư mục" này, không phải là "thư mục".
tchrist

1
Tùy thuộc vào vỏ của bạn, bạn có thể cần trích dẫn !toán tử đó : \!hoặc '!'.
Toby Speight

Câu trả lời:


32

Điều này sẽ xóa tất cả các thư mục bên trong ./myfolderngoại trừ đó ./myfolder/test2và tất cả nội dung của nó sẽ được giữ nguyên:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Làm thế nào nó hoạt động

  • find bắt đầu một lệnh tìm.
  • ./myfoldernói tìm bắt đầu với thư mục ./myfoldervà nội dung của nó.

  • -mindepth 1 không khớp với ./myfolderchính nó, chỉ các tập tin và thư mục bên dưới nó.

  • ! -regex '^./myfolder/test2\(/.*\)?' cho biết để loại trừ ( !) bất kỳ tệp hoặc thư mục phù hợp với biểu thức thông thường ^./myfolder/test2\(/.*\)?. ^phù hợp với sự bắt đầu của tên đường dẫn. Biểu thức (/.*\)?khớp với (a) một dấu gạch chéo theo sau bởi bất cứ điều gì hoặc (b) không có gì cả.

  • -delete yêu cầu tìm cách xóa các tệp phù hợp (nghĩa là không loại trừ).

Thí dụ

Hãy xem xét một cấu trúc thư mục trông giống như;

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Chúng ta có thể chạy lệnh find (không có -delete) để xem nó khớp với cái gì:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Chúng tôi có thể xác minh rằng điều này hoạt động bằng cách xem các tệp còn lại:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

1
Thay thế để -pruneđể lại các test2/*/thư mục con một mình: trở lại rm -rvà thêm -maxdepth 1.
Toby Speight

@Isaac OK. Làm xong. (Ngoài ra, +1 cho câu trả lời tuyệt vời của bạn.)
John1024

Tuyệt vời!, Nhưng xin lỗi: điều đó sẽ loại bỏ tất cả các tập tin bên trong ./myfolder. Bạn cần thiếu (IMvhO) -type dcho các thư mục .
Isaac

Ok, cái này sẽ hoạt động như bạn muốn:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
Isaac

10

Sử dụng bash :

shopt -s extglob
rm -r myfolder/!(test2)/

Thí dụ:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file

5

tl; dr

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Loại bỏ tiếng vang nếu hài lòng với danh sách các tập tin.


Sử dụng -mindepth 1sẽ đảm bảo rằng thư mục trên cùng không được chọn.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Nhưng -not -name test2sẽ không tránh được các thư mục con bên trong test2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Để làm điều đó, bạn cần một cái gì đó như tỉa:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Nhưng không sử dụng delete, vì nó ngụ ý depthvà điều đó sẽ bắt đầu xóa khỏi con đường dài nhất:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Sử dụng rm -rf(loại bỏ echonếu bạn muốn thực sự xóa):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Hoặc, cũng sử dụng maxdepthnếu tất cả những gì bạn cần là xóa các thư mục (và mọi thứ bên trong) (xóa cái echođể thực sự xóa):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

A -deletevẫn sẽ thất bại nếu thư mục không trống:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty

2

Nếu bạn đang sử dụng zsh, thì bạn có thể:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

Đã thử nghiệm với lệnh dưới đây và nó hoạt động tốt

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;

Bạn đã gặp vấn đề tương tự như OP; liệt kê / home / thư mục trên dòng lệnh (không quan trọng -mindepth 1) làm cho thư mục trên cùng khớp với tất cả các tiêu chí (đó là một thư mục và nó không có tên là "test2") và vì vậy nó bị xóa.
Jeff Schaller
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.