Відповіді:
Ось просте рішення, яке ви, ймовірно, повинні використовувати:
mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif
У .keepрозширенні нічого особливого , це просто робить так, щоб ім’я файлу тимчасово не закінчувалося .gif.
Якщо ви не повинні перейменовувати файл (і є сценарії, коли це важливо):
for X in *.gif; do
if [ "$X" != "filename.gif" ]; then
rm "$X"
fi
done
Або ви можете написати це коротше так:
for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done
Ви можете скористатися findзамість цього; це дуже потужний, ви могли б розглянути його більш зручним для читання, і це краще ручок дивних імен файлів з символами , як *в них .
find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete
Я використовував -notоператора для читабельності, але якщо важлива відповідність POSIX - якщо ви не використовуєте GNU find, або якщо це сценарій, який ви маєте намір перерозподілити іншим або запустити в різних системах - вам слід використовувати !замість оператора:
find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete
Зручна річ у findтому, що ви можете легко змінити команду на нечутливість регістру, щоб вона знаходила і видаляла файли з розширеннями як .GIF:
find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete
Зверніть увагу, що я використовував -inameзамість -nameсхеми пошуку, *.gifале я не використовував її filename.gif. Імовірно, ви точно знаєте, як називається ваш файл, і -inameбуде відповідати альтернативній великій літери не тільки в розширенні , але і в будь-якому місці імені файлу.
Усі ці рішення видаляють лише файли, що знаходяться негайно в поточному каталозі . Вони не видаляють файли, що не містяться в поточному каталозі, і не видаляють файли, що знаходяться в підкаталогах поточного каталогу.
Якщо ви хочете видалити файли скрізь, що містяться в поточному каталозі (тобто в тому числі в підкаталогах і в підкаталогах цих підкаталогів тощо) - файли, що містяться в поточному каталозі або будь-якому з його нащадків), використовуйте find без maxdepth -1 :
find . -not -name 'filename.gif' -name '*.gif' -delete
Будьте обережні з цим!
Ви також можете встановити інші значення за допомогою -maxdepth. Наприклад, для видалення файлів у поточному каталозі та його дітей та онуків, але не будь-які глибші:
find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete
Просто переконайтеся, що ви ніколи не ставите -deleteперше, перед іншими виразами! Ви побачите, що я завжди ставив -deleteу кінці. Якщо ви поставите його на початку, воно буде оцінено спочатку, і всі файли в розділі .(включаючи файли, що не закінчуються, .gifта файли в глибоких підкаталогах підподібних підрозділів .) будуть видалені!
Для отримання додаткової інформації зверніться до сторінок довідника bashі shі для команд , які використовуються в цих прикладах: mv, rm, [, і (особливо) find.
find, який є дуже універсальним.
findобробляти дивні назви файлів *у них, ніж for-loop? Цикл for обробляє файли *штрафом, оскільки ви використовували подвійні лапки.
Якщо ви використовуєте bash(оболонка за замовчуванням), extglobопція оболонки дозволяє використовувати розширений синтаксис відповідності шаблону. Щоб увімкнути це, використовуйте shoptвбудовану команду:
shopt -s extglob
(Я включаю цей рядок у свій .bashrcфайл.)
Крім усього іншого, він надає доступ !()оператору, який відповідає будь-якому шаблону, що не знаходиться в межах паролів. Для вашої мети:
rm !(filename).gif
Більш детальна інформація доступна в man bashрозділі "Узгодження шаблонів".
extglobпотрібно включити, але нічого поганого не відбувається, якщо його відключити (у такому випадку це просто не працює). І це, здається, увімкнено за замовчуванням, навіть якщо я не маю shopt -s extglobжодного з моїх (або глобальних) файлів конфігурації. Якщо є просте пояснення, чому це працює для мене поза коробкою, ви можете додати його до цієї відповіді; або я можу поставити нове запитання.
Відкрийте термінал з Ctrl+ Alt+ Tі введіть:
find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;
Різниця між -deleteі -exec rm -vf {} \;полягає в тому, що з другого варіанту ви зможете побачити, які файли було видалено через -vпрапор. Це те, що неможливо зробити з -deleteопцією. ( -name -deleteбуде надруковано імена файлів, але rmз -vвиявленням, чи вдало видалено кожен файл .)
Там є GLOBIGNOREзмінна. Від 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.
Таким чином, простий спосіб - просто встановити GLOBGINOREвказане ім'я файлу:
$ 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
Отже, у вашому випадку:
GLOBIGNORE=filename.gif; rm *.gif
Звичайно, оскільки GLOBIGNOREмістить шаблони, ви можете користуватися нею, коли потрібно виключити шаблон:
$ GLOBIGNORE='[a-c].png'; echo *.png
d.png
$ touch bd.png; GLOBIGNORE='?.png'; echo *.png
bd.png
Перевагою (?!) GLOBIGNOREЄ те, що це... налаштування автоматично виключає та не відповідає, і це дозволяє 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.
Отже, простий спосіб видалення всіх файлів і папок у каталозі:
GLOBIGNORE=.; rm -r *
Ім'я *буде відповідати назви файлів, починаючи з ., оскільки воно GLOBIGNOREввімкнено dotglob, але воно не збігається .або .., таким чином, ви не вплинете на батьківський каталог таким чином.