Удалить все файлы в каталоге, чье имя не соответствует строке в списке файлов

9

У меня есть каталог с 1000+ файлами. В текстовом файле у меня есть около 50 имен файлов, по одному на строку. Я хотел бы удалить все файлы в каталоге, имена файлов которых не соответствуют записи в списке. Какой лучший способ сделать это? Я запустил сценарий оболочки, но не смог определить правильную команду для определения имени файла в списке. Спасибо.

Натан
источник

Ответы:

8

Я понимаю, что любой вопрос, касающийся удаления файлов, должен приниматься с большой осторожностью. Мой первый ответ был слишком поспешным, я не учел тот факт, что список файлов может быть искажен для использования с egrep. Я отредактировал ответ, чтобы уменьшить этот риск.

Это должно работать для файлов, у которых нет места в имени:

Сначала перестройте свой список файлов, чтобы убедиться, что он совпадает с точным именем файла:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

построить команды rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Проверьте, подходит ли вам скрипт rm (вы можете сделать это с помощью «vim» или «less»).
Затем выполните действие:

sh -x rmscript

Если у файлов есть пробелы в имени (если у файлов есть имя "в имени, это не будет работать):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

конечно, список файлов не должен быть в одном каталоге!

ИЗДАНО:

Список файлов Натана содержал имена, соответствующие всем файлам в каталоге (например, «html» соответствует «bob.html»). Так что ничего не удалялось, потому что egrep -vfпоглотил весь поток. Я добавил команду, чтобы поставить «^» и «$» вокруг каждого имени файла. Мне повезло, что список файлов Натана был верным. Если бы он был отформатирован в DOS с завершающими строками CR-LF или с дополнительными пробелами, egrep не сохранил бы никаких файлов и все они были бы удалены.

Эммануэль
источник
Когда я запускаю команду предварительного просмотра, я получаю одну строку с «rm». Когда я запускаю реальную команду, я получаю сообщение об ошибке об отсутствующих аргументах для rm. Нужен ли специальный синтаксис для использования результатов ls | egrep во входных данных xargs?
Натан
@ Натан, ты должен сначала перейти в свой каталог. Нет специального синтаксиса. lsобеспечивает имена файлов каталога, egrep -vf filelistфильтрует ваши 50 имен файлов. Боюсь, вы удалили все свои файлы.
Эммануэль
@Emamanuel Я запускаю команду из каталога, содержащего файлы, которые нужно удалить.
Натан
@ Натан, все твои файлы удалены?
Эммануэль
нет, они все еще там.
Натан
1

Предварительно сконструируйте аргументы для find:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

Используйте echoчасти, чтобы увидеть, что будет построено. Удалите echoчасти, чтобы фактически запустить это.

Обновление: Демонстрация:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"
Кодзиро
источник
мне больше нравится этот, так как он убирает
ненужный
+1 от меня, хотя это не очень хорошо с пробелами. Возможно , некоторые одиночные кавычки ( ') следует добавить то keep=( -name \'"$REPLY"\' )и keep+=( -o -name \'"$REPLY"\' ).
Кристиан Чиупиту
вышесказанное опасно, потому что вы можете случайно удалить файлы.
Давидва
@CristianCiupitu не так ли? Я добавил демо, показывающее, что он очень хорошо справляется с пробелами.
Кодзиро
@davidva При каких обстоятельствах? Каждый раз, когда вы автоматизируете удаление вещей, вы рискуете ошибиться, но в рамках параметров вопроса я думаю, что моя демонстрация доказывает, что такой подход является правильным.
Кодзиро
1

С zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Он считывает строки filelistв массиве, а затем использует glob qualifiers / estring для выделения / выбора только имен файлов, не представленных в массиве: .выбирает только обычные файлы (добавьте, Dесли ваш список содержит точечные файлы), а отрицание ^e_'expression'_дополнительно выбирает только те, для которых которое выражение возвращает false, т.е. если их name ( $REPLY) не является элементом массива .
Если вы довольны результатом замены print -rlс rmфактически удалить файлы:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Чтобы рекурсивно выбирать и удалять файлы, используйте */**glob с ${REPLY:t}модификатором glob:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)
оборота don_crissti
источник
0

Если вы поместите содержимое каталога в файл следующим образом:

cd <somedirectory>
ls >> filelist

Откройте список файлов в текстовом редакторе и удалите все файлы, кроме тех, которые ВЫ ХОТИТЕ УДАЛИТЬ . Это смелый, потому что это противоположный подход к ответу выше

Попробуй это:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Если вы видите список файлов, выводимых на экран, замените echo rm -vследующим образом:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist
eyoung100
источник
0

Запустите приведенный ниже скрипт.

  1. Первоначально я нахожу все файлы, которые присутствуют в каталоге, и сохраняю вывод в другой файл all_files.
  2. У нас есть файл со списком файлов, которые НЕ должны быть удалены ( not_to_be_deleted_files).
  3. Я добавляю имена файлов not_to_be_deleted_filesи files_to_be_deletedв конце not_to_be_deleted_filesкак нам нужны эти 2 файла.
  4. Теперь я нахожу файлы, которые нужно удалить, используя joinкоманду linux, и перенаправляю вывод в files_to_be_deleted файл.
  5. Теперь в последнем цикле while я читаю все имена файлов files_to_be_deletedи удаляю файлы, упомянутые в этом имени файла.

Сценарий как ниже.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PS : Возможно, если вы хотите сохранить это как скрипт и запустить его, вы можете добавить имя скрипта также используя echo scriptname >> not_to_be_deleted_files.

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

Рамеш
источник
0
  • Используйте список в качестве источника, чтобы переместить все файлы в списке в новый, новый и пустой каталог сохранения.
  • Сравните количество файлов в списке и количество сохраненных файлов.
  • Если оба совпадения, удалите все несохраненные файлы вашим любимым методом.
  • Переместить сохраненные файлы обратно.
Пользователь неизвестен
источник
0

Я пошел к более безопасному и намного более быстрому подходу, потому что у меня было 18 000 файлов в списке! Мне нужно было очистить изображения в большой установке Drupal.

Удаление всех файлов, которых нет в списке, равнозначно сохранению только тех, которые находятся в списке. Поэтому я решил скопировать файлы из списка в другое место, но копирование 20 ГБ файлов заняло бы слишком много места и также было бы очень медленным. Таким образом, хитрость заключается в том, чтобы скопировать файлы hardlinks, используя вместо этого, используя -lпараметр cp. Это почти не занимает места и очень быстро. Кроме того, поскольку мне нужно было сохранить структуру каталогов, я использовал эту --parentsопцию.

Вот выдержка из моего списка файлов:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Таким образом, пример строки будет с temp, являющейся местом назначения:

cp -l --parents 'misc/feed.png' temp

Это создаст эту структуру:

temp
  misc
    feed.png

Обратите внимание, что назначение должно быть в той же файловой системе, что и источник для работы жестких ссылок.

Следующим шагом является создание сценария:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Теперь, предполагая, что вы уже создали пустой каталог dir / some / where / temp, вы можете скопировать файлы следующим образом:

sh newfilelist 2> missing_files

Обратите внимание, как ошибки заканчиваются missing_files. Дополнительным бонусом этого подхода является то, что вы получите список файлов из исходного списка, которые на самом деле не существуют!

После запуска скрипта temp будет содержать только те файлы, которые есть в списке файлов, но ничего не удаляя и не занимая дополнительное место. Если вы удовлетворены результатом, вы можете удалить все оригинальные файлы, включая подпапки.

Наконец, переместите файлы и папки из временного каталога обратно в исходное местоположение.

Для 18 000 файлов это заняло всего несколько секунд.

marlar
источник
0

Безопасно, просто.

cd в каталог.

Создайте временный каталог.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

сделанный.

paradisaeidae
источник
Добро пожаловать на сайт. Хотя ваш подход будет работать, если имена в списке, упомянутые OP, являются результатом простого сопоставления с образцом - что вполне может иметь место - обратите внимание, что OP заявил, что имена исключаемых файлов хранятся в определенном файле; Возможно, вы захотите расширить свой ответ таким образом, чтобы считывать шаблоны исключений из этого файла вместо того, чтобы полагаться на один статический шаблон, или при необходимости копировать потенциально несколько шаблонов в консоль.
AdminBee