удалите файл, но исключите все файлы в списке

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

Пример:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

Моя папка делает очистка содержит это как пример:

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Таким образом, это регистрирует, должен быть удален:

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Я ищу что-то для создания удалить команды с опцией исключить некоторые файлы, обеспеченные файлом.

16
задан 29 September 2016 в 00:03

8 ответов

Команда rm закомментирована, так что вы можете проверить и убедиться, что она работает по мере необходимости. Тогда просто откомментируйте эту строку.

Раздел check directory гарантирует, что вы случайно не запустите скрипт из неправильного каталога и не забьете неправильные файлы.

Вы можете удалить строку echo deleting для бесшумной работы.

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done
8
ответ дан 23 November 2019 в 02:34

Этот сценарий Python может сделать это:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

Важная часть должна не прокомментировать эти os.unlink() функция.

ПРИМЕЧАНИЕ : добавьте этот сценарий и dont-delete.txt к Вашему dont-delete.txt так, чтобы они оба были в списке и сохранили их в том же каталоге.

10
ответ дан 23 November 2019 в 02:34

Вот одна строка:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls печатает все файлы в текущем каталоге (в отсортированном порядке)
  2. sort dont_delete печатает все файлы, которые мы не хотите удалять в отсортированном порядке
  3. оператор <() превращает строку в файлоподобный объект
  4. Команды comm сравнивают два предварительно отсортированных файла и выводят строки для которых они различаются
  5. с использованием флагов -2 -3 заставляет comm печатать только строки, содержащиеся в первом файле, но не во втором, что будет списком файлов, которые можно безопасно удалить
  6. [ 1118] вызов tail +2 предназначен только для удаления заголовка вывода comm, который содержит имя входного файла
  7. . Теперь мы получаем список файлов, которые нужно удалить при стандартном выводе. Мы передадим этот вывод в xargs, который превратит выходной поток в список аргументов для rm. Опция -p заставляет xargs запрашивать подтверждение перед выполнением.
3
ответ дан 23 November 2019 в 02:34

Предположение, что Ваша оболочка удара имеет extglob shopt набор к на, вот является несколько более консервативной альтернативой:

rm !($(tr \\n \| < keep.txt))

(... в других отношениях превосходное предложение коммуникации сопроводительного @gardenhead!)

0
ответ дан 23 November 2019 в 02:34

FWIW это похоже на Вас, может сделать это исходно в zsh, использование (+cmd) спецификатор шарика.

Для иллюстрирования давайте запустимся с некоторых файлов

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

и файл белого списка

 % cat keepfiles.txt
foo
kazoo
bar

Во-первых, прочитайте белый список в массив:

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

или возможно лучше

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(эквивалент удара mapfile встроенный - или его синоним readarray). Теперь мы можем проверить, существует ли ключ (имя файла) в использовании массива ${keepfiles[(I)filename]} который возвращается 0, если никакое соответствие не найдено:

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

Мы можем использовать это для создания функции, которая возвращается true при отсутствии соответствий для $REPLY в массиве:

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

Наконец, мы используем эту функцию в качестве спецификатора в нашей команде:

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

или, в Вашем случае

 % rm -- *(+nokeep)

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

1
ответ дан 23 November 2019 в 02:34

Принятие там не является никаким пробелом (Пробелы/Вкладки) в Ваших файлах, перечисленных в названном файле list, затем Вы сделали бы:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \)

Просто добавьте -delete к команде выше для удаления файлов, который не существует в файле списка. Если Ваша находка не имеет -delete опция можно использовать rm с -exec как следующее:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} \;

Или использование -exec с + разделитель вместо этого.

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} +

echo просто привык к пробному прогону.

0
ответ дан 23 November 2019 в 02:34

Мое предложение:

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

Обновление 07.08.2018

Пример:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

Отметьте после строки 3, Вы будете иметь dont-delete.txt файл с содержанием:

./a
./b
./dont-delete.txt

(продвижение ./ очень важно),

Файлы c и d будет удален.

-1
ответ дан 23 November 2019 в 02:34

Если вывод ls /home/me/myfolder2tocleanup/ превышает максимальный предел аргумента оболочки ARG_MAX который составляет приблизительно 2 МБ для Ubuntu, я предложил бы следующее.


Одна строка управляет реализацией, которая сделает задание, был бы следующие:

  1. Скопируйте dont-delete.txt файл к каталогу, содержащему файлы, которые будут удалены как так:
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd к каталогу, содержащему файлы, которые будут удалены как так:
cd /home/me/myfolder2tocleanup/
  1. Сделайте пробный прогон, чтобы протестировать команду и заставить ее распечатать названия файлов, которые она обнаруживает, чтобы быть удаленной, на самом деле не удаляя их, как так:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. Если Вы удовлетворены выводом, удаляете файлы путем выполнения команды как так:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

Explaination:

  • ls -p перечислит все файлы и каталоги в текущем каталоге и опции -p добавит a / к именам каталогов.
  • grep -v / исключит каталоги путем удаления всех объектов, содержащих a / на их имена.
  • sed 's/\<dont-delete.txt\>//g'исключит dont-delete.txt файл, таким образом, это не становится удаленным в процессе.
  • sort будет, только чтобы удостовериться, отсортировать остающийся вывод ls.
  • comm -3 - <(sort dont-delete.txt) отсортирует dont-delete.txt файл, сравните его с отсортированным выводом ls и исключите имена файлов, которые существуют в обоих.
  • xargs rm удалит все остающиеся имена файлов в уже обработанном выводе ls. Это означает, что все объекты в текущем каталоге будут удалены за исключением каталогов, файлы, перечисленные в dont-delete.txt файл и dont-delete.txt сам файл

В части пробного прогона:

  • xargs echo распечатает файлы, которые должны быть удалены.
  • tr " " "\n" переведет пробелы в новые строки для более легкой удобочитаемости.
0
ответ дан 23 November 2019 в 02:34

Другие вопросы по тегам:

Похожие вопросы: