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


215

При использовании sudo rm -r, как я могу удалить все файлы, за исключением следующего:

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

5
Похоже, вопрос для unix.stackexchange.com
Джейсон

1
Есть 2 способа прочитать этот вопрос, и существующие ответы охватывают обе интерпретации: ЛИБО: (а) сохраняйте файлы с указанными именами, непосредственно расположенные в целевом каталоге, и - как это rm -rподразумевается - удаляйте все остальное, включая подкаталоги, - даже если они содержат файлы с указанными именами; ИЛИ: (b) пройти по всему поддереву целевого каталога и в каждом каталоге удалить все файлы, кроме файлов с именами в списке.
mklement0

Ответы:


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

Если вы не укажете, -type ffind также выведет список каталогов, которые вам могут не понадобиться.


Или более общее решение с использованием очень полезной комбинации 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 Shen

5
как насчет каталогов? он удалит все файлы, но удалит ли он папки ?!
orezvani

31
Вместо «| xargs rm» команда find принимает параметр -delete.
Эмиль Стенстрём,

1
вместо -print0 | xargs -0 rm --тебя можно просто-delete
Энди

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

Extglob (Extended Pattern Matching) должен быть включен в BASH (если он не включен):

shopt -s extglob

2
Когда я это делаю, я получаю "синтаксическую ошибку рядом с неожиданным токеном` ('" shopt -s extglob; rm -rf !(README|LICENSE). Есть идеи почему?"
Денис

@ nnic Я не помню, извини. Я, вероятно, в конечном итоге использовать findс -deleteопцией.
Деннис

Это лучшее решение для меня, и оно работает по умолчанию на моей Ubuntu 12.04.4 LTS без необходимости покупки
xtian

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

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(у вас есть права root, верно?), Переместит файлы, которые вы перечислили в этот каталог, рекурсивно удалите все в текущем каталоге (вы знаете, что вы находитесь в правильном каталоге, не так ли?), Переместите вернуться к текущему каталогу все /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работает намного быстрее, так как не нужно детализировать каталоги без необходимости.
Биллиноа

Повторный 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 *)
mklement0

19

Я предпочитаю использовать список подзапросов:

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

-v, --invert-match выбрать несовпадающие строки

\| Разделитель


1
Элегантное решение
Джошуа Салазар

9

Так как никто не упомянул это:

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

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

2
@RemusAvram Вы можете использовать соответствующие ключи с cpили rsyncдля сохранения разрешений. В любом случае, это просто альтернативный метод (приведенный в качестве предложения), который имеет здесь свое место в качестве ответа на ФП.
gniourf_gniourf

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

@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 ) в Баше, я делаю это в ежедневной рутинной основе, в течение нескольких Маков в лабораториях: 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 *.

Затем переместите необходимые файлы в текущий каталог.


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

-3

Удалить все, кроме файла. Name:

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

2
Это приведет к ужасной ошибке и может привести к потере данных, если в вашем каталоге / файлах есть пробелы или необычные символы. Вы никогда не должны анализировать ls. mywiki.wooledge.org/ParsingLs
RJ
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.