Câu trả lời:
Đâ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ề .keep
phầ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 find
thay 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 -not
toá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 find
là 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 -iname
thay -name
cho mẫu tìm kiếm *.gif
như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à -iname
sẽ 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 .gif
và 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 bash
và sh
và cho các lệnh được sử dụng trong các ví dụ: mv
, rm
, [
, và (đặc biệt) find
.
find
, rất linh hoạt.
find
xử 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.
Nếu bạn đang sử dụng bash
(shell mặc định), extglob
tù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 shopt
lệnh dựng sẵn:
shopt -s extglob
(Tôi bao gồm dòng đó trong .bashrc
tậ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".
extglob
phả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 extglob
trong 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.
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
và -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ì -v
cờ. Đó là điều không thể được thực hiện với -delete
tùy chọn. ( -name -delete
Sẽ in tên tập tin, nhưng rm
với -v
tiết lộ nếu mỗi tập tin được thành công xóa.)
Có GLOBIGNORE
biế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 GLOBGINORE
tê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ì GLOBIGNORE
có 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ế (?!) GLOBIGNORE
Là cài đặt nó tự động loại trừ .
và..
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 đó.