Как удалить все файлы в каталоге, кроме некоторых?


123

Мне нужно удалить все файлы в каталоге, но исключить некоторые из них. Например, в каталоге с файлами a b c ... zмне нужно удалить все, кроме uи p. Есть простой способ сделать это?


Ответы ниже намного лучше, но вы можете просто сделать файлы для сохранения только для чтения, удалить все, а затем изменить их обратно на исходные права (если вы не используете rm -f). Вы должны были бы знать, какие разрешения восстанавливать, и вы должны знать, что ничто не требовало доступа к ним для записи во время процесса. Вот почему другие ответы лучше.
Джо

1
Если вы также хотите удалить скрытые файлы, запустите shopt -s dotglobперед запуском rm (...).

Ответы:


109

Что я делаю в этих случаях, чтобы набрать

rm *

Затем я нажимаю Ctrl+ X, *чтобы развернуть * все видимые имена файлов.

Затем я могу просто удалить два файла, которые я хочу сохранить из списка, и, наконец, выполнить командную строку.


25
Я думаю, это работает только до тех пор, пока список файлов, который *расширяется, не становится слишком длинным. : -}
Фрерих Раабе

9
Esc, сопровождаемый *, также расширит "*".
slowpoison

2
@SantoshKumar: Это не имеет смысла для меня. Расширение всегда будет работать, оно не зависит от того, какую команду вы хотите использовать впоследствии.
Der Hochstapler

2
@OliverSalzburg К сожалению, комбинация немного сбивает с толку. Я думаю, что вы должны написать как Ctrl+ Shift+ x+*
Сантош Кумар

2
@SantoshKumar: Но это не комбинация.
Der Hochstapler

144

Для rmвсех, кроме u,pBash просто введите:

rm !(u|p)

Для этого необходимо установить следующую опцию:

shopt -s extglob

Смотрите больше: glob - Greg's Wiki


1
у вас должен быть активен "extglobbing": shopt -s extglob
sparkie

18
Тебе нужно shopt -s extglob, @Ashot. Кроме того, это просто файлы, а не каталоги, поэтому я удалил -rfопции в вашей команде.
Slhck

3
Если необходимо исключить один файл из выбора файлов, попробуйте следующее: rm !(index).html. Это удалит все файлы, оканчивающиеся на «.html», за исключением «index.html».
Мзутер

71

Ты можешь использовать find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! отменяет следующее выражение
  • -name указывает имя файла
  • -maxdepth 1заставит процесс поиска только указанную директорию ( findпо умолчанию проходит каталоги)
  • -type f будет обрабатывать только файлы (а не, например, каталоги)
  • -delete удалит файлы

Затем вы можете настроить условия, просмотрев справочную страницу поиска.

Обновить

  • Имейте в виду, что порядок элементов выражений является значительным (см. Документацию)
  • Сначала проверьте свою команду, используя -printвместо-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print

5
порядок предикатов здесь имеет решающее значение. Если один положить -deleteсразу после .этого будет катастрофа (удалит все файлы в CWD)
Михал Шрайер

Это можно записать более компактно, какfind . -maxdepth 1 -type f -name '[^up]' -delete
Кодзиро

4
@kojiro да, но только для файлов, состоящих всего из одной буквы. С более сложными именами регулярное выражение может быть беспорядком.
Маттео

2
findмой лучший друг, особенно когда слишком много файлов, чтобы их потерять
Теренс Джонсон

43

Просто:

mvфайлы, которые вы хотите в верхнем каталоге, rmкаталог, а затем mvих обратно.


13
Конечно, мв их в каталог выше. Постарайтесь не переносить их в подкаталог, который вы
удаляете

@Konerak: rmбез -rне удалит подкаталоги.
reinierpost

11
Это перезапишет файлы с одинаковыми именами в каталоге назначения
Matteo

7
Я не одобряю это, потому что, хотя это может быть удобно, оно также не является атомарным и эффективно удаляет все файлы из каталога в течение короткого периода времени; это было бы неприемлемо, если, например, файлы совместно используются в сети.
Сэм Хоцевар

15

В некоторой степени похож на этот ответ, но никаких специальных опций не требуется, насколько я знаю, что «древняя» функциональность поддерживается любой (смутно) / bin / sh, похожей на оболочку (например, bash, zsh, ksh и т. Д.)

rm [^up]

2
Это работает для 1-символьных имен файлов. Для длинных имен лучше ответ Спарки.
Гленн Джекман

3
Что было бы не так с rm [^up]*? Я делаю подобные вещи довольно часто.
CVN

3
@ MichaelKjörling - это удалит все файлы, начинающиеся с u или p, а не только те, которые имеют имена u и p. Я думаю, что OP (@Ashot) означало az и u, p и т. Д. символически, а не буквально.
Судипта Чаттерджи

4
@HobbesofCalvin Это удалит все файлы, не начинающиеся с u или p, а не те, которые начинаются с них.
rjmunro

@rjmunro - спасибо, пропустил это! :)
Судипта Чаттерджи

11

Делаем это без поиска:

ls | grep -v '(u|p)' | xargs rm

(Отредактируйте: «u» и «v», как и в других местах здесь, используются в качестве универсальных версий целых регулярных выражений. Очевидно, что вам нужно быть осторожным, чтобы привязать свои регулярные выражения, чтобы избежать совпадения слишком многих вещей.)

Вы определенно будете хотеть сценарий, если вы собираетесь делать большую часть этого, как предлагали другие.


grep не будет обрабатывать расширенное регулярное выражение по умолчанию: либо используйте, -Eлибоegrep
Matteo

2
это исключит любой файл, содержащий uилиp
Маттео

@ Matteo Нет, не будет. Grep не grep файлы, это grep вывод команды ls. Вы думаете о чем-то вроде grep -L (u|p)' * | xargs rmгде -Lозначает список имен файлов, не содержащих совпадения.
rjmunro

4
О, вы имеете в виду любой файл, имя которого содержит uили pне любой файл, содержащий uили p. Это правильно. Вы можете исправить с помощьюegrep -v '^(u|p)$'
rjmunro

1
Вот удалите все, кроме этих матчей! ls | grep -v 'vuze\|progs' | xargs rm -rf
Ник

6

В зш:

setopt extended_glob  # probably in your .zshrc

затем

rm ^(u|p)

или же

rm *~(u|p)

Второй будет работать , даже если у вас есть ^в $histcharsтечение подмены истории, и, конечно , вы можете поставить произвольную Glob перед ~.


5

GLOBIGNORE берет разделенный двоеточиями список

GLOBIGNORE=u:p
rm *

12
Это не работает на моей оболочке (GNU bash 4.1.5 (1)). Обязательно сначала протестируйте его с помощью чего-то менее опасного, чемrm в каталоге тестирования!
CVN

3

Еще в эпоху дискет у меня был исполняемый файл dos под названием «Кроме», который временно перемещал вещи из текущего каталога и выполнял команду, так что вы могли бы сказать:

кроме * .txt del *. *

удалить все, кроме ваших текстовых файлов.

Это было бы довольно тривиально реализовать в виде сценария оболочки, и если вы будете делать это более двух раз, кажется, что это хорошая идея.


2
Это напомнило мне то же самое. Но временное перемещение из папки не может быть хорошей идеей в эпоху многозадачности :)
Седат Капаноглу

3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Это удалит все файлы, кроме U и P в Unix


2

Для тех, кто предпочитает указывать произвольные сложные шаблоны исключений (охватывающие все затронутые имена файлов) в полном стиле remaxp emacs, posix-awk или posix-extended (см. Страницу поиска man), я бы порекомендовал этот. Это исключает uи pв текущем dir в этом примере. Это может быть удобно для сценариев.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf

Вам нужно указать каталог перед выражением (`find. -Regextype ...).
Маттео

-regextypeбудет работать только на версиях GNU
Matteo

нет - моя версия find (debian squeeze) определенно не требует явного каталога перед выражением, если должен использоваться текущий каталог
sparkie

@sparke: это работает только в реализациях GNU
Маттео

@sparkie: не определять каталог (первый параметр) для findрасширения findкоманды GNU . То же самое относится и к -regextypeварианту. Кроме того, ваша команда также удалит файлы в подкаталогах, тогда как оригинальный вопрос четко задан относительно файлов в каталоге.
Микко Ранталайнен,

1

Я всегда использую:

rm [a-o,q-t,v-z]*

Это позволит вам определить, насколько гранулярным вы хотите это сделать. Поэтому, если вы хотите удалить файлы от 0 до 3, вы можете использовать:

rm [a-o,z]*

1

Еще одна версия с использованием xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Обратите внимание, что xargs -Iэто необходимо для правильной обработки имен файлов, включая пробелы.


1

Еще один:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

Это довольно долго, и я не знаю, сможете ли вы легко превратить это в функцию, которая может легко разместить произвольное количество аргументов, но это работает хорошо.

И это чистая доброта.


1

Вот еще один вариант. Вы можете ввести:

rm -i *

или же:

rm --interactive *

Поэтому rmпопросит вас подтвердить удаление каждого файла.


1

Использование:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

чтобы удалить все файлы, включая каталоги, кроме файлов u, p и .ext.


0

Простой способ, который сложно испортить: допустим, вы хотите удалить все, кроме * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.