Xóa các tệp có phần mở rộng nhất định trừ một tệp khỏi thiết bị đầu cuối


36

Tôi cần xóa tất cả các tệp có đuôi .gif ngoại trừ một tệp có tên là "filename.gif". Cách tối ưu để làm điều này trong thiết bị đầu cuối là gì?

Lệnh rm *.gifloại bỏ tất cả các tệp gif bao gồm cả tệp filename.gif.

Câu trả lời:


66

Đây là giải pháp đơn giản mà bạn có thể nên sử dụng:

mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif

Không có gì đặc biệt về .keepphần mở rộng, điều này chỉ làm cho nó để tên tệp tạm thời không kết thúc .gif.

Nếu bạn không được đổi tên tệp (và có các tình huống kịch bản trong đó điều này rất quan trọng):

for X in *.gif; do
    if [ "$X" != "filename.gif" ]; then
        rm "$X"
    fi
done

Hoặc bạn có thể viết nó ngắn hơn như thế này:

for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done

Bạn có thể thích sử dụng findthay thế; nó rất mạnh, bạn có thể xem nó dễ đọc hơn và xử lý tốt hơn các tên tập tin kỳ lạ với các nhân vật như *trong đó .

find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete

Tôi đã sử dụng -nottoán tử để dễ đọc, nhưng nếu tuân thủ POSIX là quan trọng - nếu bạn không sử dụng GNU find hoặc nếu đây là tập lệnh bạn định phân phối lại cho người khác hoặc chạy trên nhiều hệ thống khác nhau - bạn nên sử dụng !toán tử thay thế:

find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete

Một điều tiện lợi findlà bạn có thể dễ dàng sửa đổi lệnh không phân biệt chữ hoa chữ thường, để nó tìm và xóa các tệp có phần mở rộng như .GIF:

find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete

Xin lưu ý rằng tôi đã sử dụng -inamethay -namecho mẫu tìm kiếm *.gifnhưng tôi chưa sử dụng nó cho filename.gif. Có lẽ bạn biết chính xác tệp của bạn được gọi là gì và -inamesẽ khớp với viết hoa thay thế không chỉ trong phần mở rộng , mà bất kỳ nơi nào trong tên tệp.

Tất cả các giải pháp này chỉ xóa các tập tin cư trú ngay lập tức trong thư mục hiện tại . Họ không xóa các tệp không có trong thư mục hiện tại và họ không xóa các tệp nằm trong thư mục con của thư mục hiện tại.

Nếu bạn muốn xóa các tệp ở mọi nơi có trong thư mục hiện tại (nghĩa là bao gồm trong các thư mục con và thư mục con của các thư mục con đó, v.v. - các tệp có trong thư mục hiện tại hoặc bất kỳ hậu duệ nào của nó), hãy sử dụng find mà không maxdepth -1 :

find . -not -name 'filename.gif' -name '*.gif' -delete

Hãy cẩn thận với điều này!

Bạn cũng có thể đặt các giá trị khác với -maxdepth. Ví dụ: để xóa các tệp trong thư mục hiện tại và con cháu của nó nhưng không sâu hơn:

find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete

Chỉ cần chắc chắn rằng bạn không bao giờ đặt -deleteđầu tiên, trước các biểu thức khác! Bạn sẽ thấy tôi luôn luôn đặt -deleteở cuối. Nếu bạn đặt nó ở đầu, nó sẽ được đánh giá đầu tiên và tất cả các tệp trong .(bao gồm các tệp không kết thúc .gifvà các tệp trong thư mục phụ phụ phụ sâu .) sẽ bị xóa!

Để biết thêm thông tin , vui lòng xem trang hướng dẫn cho bashshvà cho các lệnh được sử dụng trong các ví dụ: mv, rm, [, và (đặc biệt) find.


1
Cảm ơn Eliah. Tôi đã làm nó tương tự như phương pháp đầu tiên mà bạn đã đề xuất tức là chuyển đổi tệp theo định dạng khác và chuyển đổi lại. Nhưng điều đó có vẻ hơi tối ưu và ô uế. Tôi thích cách tiếp cận thứ hai mà bạn và @efthialex đã đề xuất và tôi đang sử dụng nó ngay bây giờ. Cảm ơn!

1
@Marvis Tôi rất vui vì điều này đáp ứng nhu cầu của bạn. Nhân tiện, tôi đã mở rộng câu trả lời này bằng thông tin về một phương thức khác (hoặc lớp phương thức) bằng cách sử dụng find, rất linh hoạt.
Eliah Kagan

3
Cảm ơn câu trả lời chi tiết findthực sự là một tìm kiếm tốt.

1
+1 cho câu trả lời chung (di chuyển-xóa-di chuyển).
tu-Tái lập Monica-dor duh

Nit-pick: làm thế nào để findxử lý tên tập tin kỳ lạ với *chúng tốt hơn vòng lặp for? Vòng lặp for xử lý các tệp *tốt, vì bạn đã sử dụng dấu ngoặc kép.
Flimm

28

Nếu bạn đang sử dụng bash(shell mặc định), extglobtùy chọn shell cho phép bạn sử dụng cú pháp khớp mẫu mở rộng. Để kích hoạt nó, hãy sử dụng shoptlệnh dựng sẵn:

shopt -s extglob

(Tôi bao gồm dòng đó trong .bashrctập tin của tôi .)

Trong số những thứ khác, nó cấp quyền truy cập cho !()toán tử, phù hợp với bất kỳ mẫu nào không nằm trong parens. Vì mục đích của bạn:

rm !(filename).gif

Thông tin thêm có sẵn trong man bash"Kết hợp mẫu".


1
Câu trả lời tuyệt vời! Nó đặc trưng cho bash vì vậy có thể không phù hợp với kịch bản di động, nhưng các tác vụ tương tác và thậm chí một số kịch bản, đây là cách tốt nhất để thực hiện. Nó mang thêm sự phức tạp extglobphải được kích hoạt, nhưng không có gì xấu xảy ra nếu nó bị vô hiệu hóa (trong trường hợp đó, điều này chỉ không hoạt động). Và nó dường như được bật theo mặc định, mặc dù tôi không có shopt -s extglobtrong bất kỳ tệp cấu hình nào (hoặc toàn cầu). Nếu có một lời giải thích đơn giản về lý do tại sao nó hoạt động cho tôi ra khỏi hộp, bạn có thể muốn thêm nó vào câu trả lời này; hoặc tôi có thể gửi một câu hỏi mới.
Eliah Kagan

13

Mở Terminal bằng Ctrl+ Alt+ Tvà gõ:

find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;

Sự khác biệt giữa -delete-exec rm -vf {} \;là với tùy chọn thứ hai, bạn sẽ có thể xem tập tin nào đã bị xóa, vì -vcờ. Đó là điều không thể được thực hiện với -deletetùy chọn. ( -name -deleteSẽ in tên tập tin, nhưng rmvới -vtiết lộ nếu mỗi tập tin được thành công xóa.)


1

GLOBIGNOREbiến. Từ man bash:

GLOBIGNORE
      A colon-separated list of patterns defining the set of filenames
      to be ignored by pathname expansion.  If a filename matched by a
      pathname expansion pattern also matches one of the  patterns  in
      GLOBIGNORE, it is removed from the list of matches.

Vì vậy, một cách đơn giản là chỉ đặt GLOBGINOREtên tệp trong câu hỏi:

$ touch {a,b,c,d}.png
$ echo *.png
a.png b.png c.png d.png
$ GLOBIGNORE=c.png
$ echo *.png
a.png b.png d.png

Vì vậy, trong trường hợp của bạn:

GLOBIGNORE=filename.gif; rm *.gif

Tất nhiên, vì GLOBIGNOREcó chứa các mẫu, bạn có thể sử dụng nó bất cứ khi nào bạn muốn loại trừ một mẫu:

$ GLOBIGNORE='[a-c].png'; echo *.png
d.png
$ touch bd.png; GLOBIGNORE='?.png'; echo *.png
bd.png

Một lợi thế (?!) GLOBIGNORELà cài đặt nó tự động loại trừ ... không khớp, và nó cho phép dotglob:

The  GLOBIGNORE shell variable may be used to restrict the set of file‐
names matching a pattern.  If GLOBIGNORE is set, each matching filename
that also matches one of the patterns in GLOBIGNORE is removed from the
list of matches.  The filenames ``.''  and ``..''  are  always  ignored
when  GLOBIGNORE is set and not null.  However, setting GLOBIGNORE to a
non-null value has the effect of enabling the dotglob shell option,  so
all other filenames beginning with a ``.''  will match.  To get the old
behavior of ignoring filenames beginning with a ``.'', make ``.*''  one
of  the  patterns  in  GLOBIGNORE.  The dotglob option is disabled when
GLOBIGNORE is unset.

Vì vậy, một cách đơn giản để xóa tất cả các tệp và thư mục trong một thư mục:

GLOBIGNORE=.; rm -r *

Tên *tệp sẽ khớp với tên bắt đầu bằng ., kể từ khi GLOBIGNOREđược bật dotglob, nhưng nó sẽ không khớp .hoặc ..vì vậy bạn sẽ không ảnh hưởng đến thư mục mẹ theo cách đó.

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.