Видаліть усі файли, крім деяких, із каталогу


215

Як користуватися sudo rm -r, як я можу видалити всі файли, за винятком наступного:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
Звучить питання для unix.stackexchange.com
Джейсон

1
Є два способи прочитати це запитання, і існуючі відповіді охоплюють обидві інтерпретації: EITHER: (a) зберігати файли із вказаними іменами, безпосередньо розташованими в цільовому каталозі, та - як rm -rвипливає з цього - видалити все інше, включаючи підкаталоги - навіть якщо вони містять файли із вказаними іменами; АБО: (b) проходьте все піддірець цільового каталогу та видаліть у кожному каталозі всі файли, крім тих, що мають перелічені імена.
mklement0

Відповіді:


219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

Якщо ви не вказали -type fпошук, ви також побачите каталоги, які ви, можливо, не хочете.


Або більш загальне рішення з використанням дуже корисної комбінації find | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

наприклад, видаліть усі файли, що не містять txt, у поточному каталозі:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

print0І -0комбінація необхідна , якщо є прогалини в будь-якому з імен файлів , які повинні бути видалені.


2
здається, у xargs є обмеження розміру тексту
frazras

26
для видалення кількох шаблонів:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen 申思维

5
як щодо каталогів? він видалить усі файли, але чи видаляє папки ?!
орезвані

31
Замість "| xargs rm" знайдіть параметр -delete.
Еміль Стенстрем

1
замість -print0 | xargs -0 rm --вас можна просто-delete
Енді,

151
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

Екстраглоб (розширене узгодження шаблону) повинен бути включений у BASH (якщо він не включений):

shopt -s extglob

2
Я отримую "помилку синтаксису поблизу несподіваного маркера` ('", коли я це роблю shopt -s extglob; rm -rf !(README|LICENSE). Будь-яка ідея, чому?
Денніс

@nic Я не пам'ятаю, вибач. Я, ймовірно, в кінцевому рахунку використовував findцей -deleteваріант.
Денніс

Це найкраще рішення для мене, і воно працює за замовчуванням на моїй Ubuntu 12.04.4 LTS без необхідності в
магазині

3
@nic, @Dennis: Помилка синтаксису говорить про те, що bashбуло використано щось ІНШЕ , наприклад dash, де extglobне підтримується. Однак в інтерактивній bash оболонці команда ТАКОЖ не працюватиме, як зазначено, хоча з різних причин. Короткий зміст: виконати shopt -s extglobІТСЕЛЬНО; ЯКЩО УСПІШНО ВКЛЮЧЕНО (перевірити shopt extglob), виконати rm -rf !(README|LICENSE). (Поки extglobце ще не ввімкнено, !(...)оцінюється розширенням історії ДО ПЕРЕД виконання команд; оскільки це, швидше за все, не виконується, команда extglob
NEITHER

2
@nic, @Dennis, @ mklement0: У мене була така сама проблема із "синтаксичною помилкою біля несподіваного маркера (" під час виконання команди у файлі .sh (#! / bin / bash), але не тоді, коли я запускав її в команді Виявилося, що, крім shopt -s extglobзапуску в інтерфейсі командного рядка, мені довелося перезапустити його всередині мого файлу сценаріїв. Це вирішило для мене проблему.
Ahresse

41

find . | grep -v "excluded files criteria" | xargs rm

Тут буде перераховано всі файли в поточному каталозі, а потім перераховано всі ті, що не відповідають вашим критеріям (остерігайтеся відповідності імен каталогів), а потім видаліть їх.

Оновлення : на основі вашої редакції, якщо ви дійсно хочете видалити все з поточного каталогу, крім перелічених файлів, це можна використовувати:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

Це створить каталог резервного копіювання /tmp_backup(у вас є кореневі привілеї, правда?), Перемістіть файли, які ви перерахували до цього каталогу, видалить рекурсивно все в поточному каталозі (ви знаєте, що ви в правильному каталозі, чи не так?), Перемістіть повернутися до поточного каталогу все, /tmp_backupі, нарешті, видалити /tmp_backup.

Я вибираю каталог резервного копіювання, що знаходиться в корені, тому що якщо ви намагаєтесь видалити все рекурсивно з кореня, у вашої системи виникнуть великі проблеми.

Звичайно, є більш елегантні способи зробити це, але цей досить простий.


2
Дуже добре працює і з функцією egrep, наприклад, для очищення проміжних файлів з латексу:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz

дивовижна команда! для видалення каталогів просто змініть на rm -r
Aris

1
Якщо ви хочете просто видалити все з поточного каталогу, окрім виключених критеріїв: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rпрацює набагато швидше, оскільки не потрібно надмірно деталізувати до каталогів.
billynoah

Щодо findконвеєра: проблеми з ефективністю (у тому числі 3 команди використовуються для того, що findможна зробити поодинці), це не працюватиме за призначенням з назви файлів із вбудованими пробілами та потенційно видалить неправильні файли.
mklement0

Команда, яка зберігає файли "для збереження" в іншому місці ( /tmp_backup), не закінчується добре, якщо вона перервана - з точки зору користувача, всі файли зникли, якщо вони не знають, куди їх шукати, щоб повернути їх назад . З цієї причини я не прихильник такого типу стратегії.
Крейг МакКуін


19

Ви можете використовувати змінну середовища GLOBIGNORE в Bash.

Припустимо, ви хочете видалити всі файли, крім php та sql, тоді ви можете зробити наступне -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

Якщо встановити GLOBIGNORE, подібне до цього, ігнорується php та sql з символів, які використовуються на зразок "ls *" або "rm *". Отже, використовуючи "rm *" після встановлення змінної, буде видалено лише файл txt і tar.gz.


6
+1; Більш простою альтернативою встановлення та відновлення GLOBIGNOREзмінної є використання (GLOBIGNORE='*.php:*.sql'; rm *)
підшару

19

Я вважаю за краще використовувати список запитів:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, - невідповідні лінії виберіть невідповідні лінії

\| Роздільник


1
Елегантне рішення
Джошуа Салазар

9

Оскільки про це ніхто не згадував:

  • скопіюйте файли, які не хочете видалити, у безпечне місце
  • видалити всі файли
  • поверніть скопійовані файли на місце

2
Це складніше, оскільки вам потрібно подбати про дозволи, після того як ви скопіюєте їх назад.
Ромул

2
@RemusAvram Ви можете використовувати відповідні комутатори з cpабо rsyncзберегти дозволи. У будь-якому випадку це лише альтернативний метод (дається як пропозиція), який має тут своє місце, як відповідь на ОП.
gniourf_gniourf

Це може виявитися недоцільним у багатьох ситуаціях, коли збережені файли активно використовуються іншими процесами. Також громіздкі файли, які потрібно видалити, - це лише невелика підмножина, і задіяна велика кількість файлів.
кодове літо

@codeforester: обов'язково. Але є ситуації, коли це доречно, хоча ... насправді я не бачу сенсу вашого коментаря :).
gniourf_gniourf

6

Ви можете написати цикл для цього ...%)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

6

Трохи запізнюємось на ОП, але, сподіваємось, корисно для всіх, хто потрапить сюди набагато пізніше через Google ...

Я знайшов відповідь @awi та прокоментувати -delete від @Jamie Bullock дуже корисно. Проста утиліта, щоб ви могли це робити в різних каталогах, ігноруючи різні імена файлів / типів кожного разу з мінімальним введенням тексту:

rm_except (або як ви хочете назвати його)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

наприклад, щоб видалити все, крім текстових файлів та foo.bar:

rm_except *.txt foo.bar 

Схожий на @mishunika, але без пункту if.


5

Якщо ви користуєтесь цим, zshя дуже рекомендую.

rm -rf ^file/folder pattern to avoid

З extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

Спробувавши це, працювали з:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

але назви з пробілами (як завжди) важкі. Спробував також Virtualbox\ VMsзамість цитат. Він завжди видаляє цей каталог ( Virtualbox VMs).


НЕ працює для файлів. rm !(myfile.txt)вилучає все, включаючиmyfile.txt
хаверім

слід виконати shopt -s extglobспочатку, як вказував @ pl1nk
zhuguowei

Так, дуже важливо активувати розширений глобулінг ( extglob ) у баші , я роблю це у щоденній рутинній роботі, протягом кількох Macs у лабораторіях: shopt -s extglobа потім cd /Users/alumno/і, нарешті, rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) читайте про розширений глобус тут
juanfal

4

Просто:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

Або:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

Це не рекомендується. Розбір lsрезультатів може стати проблемою. Детальну інформацію див. Тут
RJ

2

Зробіть файли незмінними. Навіть root не зможе видалити їх.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

Усі інші файли видалено.
Врешті-решт ви можете скинути їх із змін.

chattr -i *

0

Це схоже на коментар від @ siwei-shen, але вам потрібно -oпрапор, щоб зробити кілька зразків. -oПрапор стоїть за «або»

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

Це можна зробити за допомогою двох послідовностей команд. Спочатку визначте масив із назвою файлів, які ви не хочете виключати:

files=( backup.tar.gz script.php database.sql info.txt )

Після цього перегляньте всі файли в каталозі, який ви хочете виключити, перевіривши, чи є ім'я файлу в масиві, який ви не хочете виключати; якщо його не, то видаліть файл.

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

Порівняння регулярних виразів невірно - воно збереже будь-який файл, ім'я якого є підрядком одного із захищених файлів (хоча навколишні пробіли дещо пом'якшують це; але імена файлів можуть містити пробіли). Ви повинні зібрати масив усіх файлів, потім відняти файли, які ви хочете виключити з цього масиву, а потім видалити решта файлів.
tripleee

-1

Оскільки про це ще ніхто не згадував, в одному конкретному випадку:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(або просто rm $OLD_FILES )

або

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

Можливо, вам доведеться використовувати, shopt -s nullglobякщо деякі файли можуть бути там чи ні:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

без нульглобу, echo *.sh *.bash може дати вам "a.sh b.sh * .bash".

(Сказавши все це, я сам віддаю перевагу цій відповіді , хоча це не працює в OSX)


Існуюча відповідь Леонардо Ермосо робить це з меншою кількістю помилок. Це не вдасться для імен файлів з пробілами; використовуючи масив елегантно вирішує цю конкретну проблему (а також менш суттєво уникає використання великих літер для його приватних змінних, чого, як правило, слід уникати).
tripleee

-3

Замість того, щоб переходити до прямої команди, будь-ласка, перемістіть потрібні файли, щоб тимчасово змінити режим поточного режиму. Потім видаліть усі файли за допомогою rm *абоrm -r * .

Потім перемістіть потрібні файли до поточного режиму.


Це може виявитися недоцільним у багатьох ситуаціях, коли збережені файли активно використовуються іншими процесами. Також громіздкі файли, які потрібно видалити, - це лише невелика підмножина, і задіяна велика кількість файлів.
кодове літо

-3

Видаліть усе виключити ім'я файлу:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

2
Це жахливо вийде з ладу і може призвести до втрати даних, якщо у вашому каталозі / файлах є пробіли або незвичні символи. Ніколи не слід розбирати лс. mywiki.wooledge.org/ParsingLs
RJ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.