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

17

У меня есть файл манифеста, который является просто списком имен, разделенных новой строкой. Как удалить все файлы с именем not в манифесте из папки?

Я попытался построить команду find ./ ! -name "filename" динамически:

command="find ./ ! -name \"MANIFEST\" "
for line in 'cat MANIFEST'; do
    command=${command}"! -name \"${line}\" " 
done
command=${command} -exec echo {} \;
$command

Но файлы остаются.

[Примечание:] Я знаю, что это использует эхо. Я хочу проверить, что моя команда делает, прежде чем использовать его.

Решение: (спасибо PixelBeat )

ls -1 > ALLFILES
sort MANIFEST MANIFEST ALLFILES | uniq -u | xargs rm

Без временного файла:

ls -1 | sort MANIFEST MANIFEST - | uniq -u | xargs rm

Игнорирует, отсортированы ли файлы / нет.

    
задан brice 06.05.2010 в 18:12
источник
  • Спасибо всем! Я даю ему pixelbeat для своего руководства по оболочке, в котором содержится решение –  brice 08.05.2010 в 13:57

5 ответов

11

Используя шаблон «set difference» из Ссылка

(find ./ -type f -printf "%P\n"; cat MANIFEST MANIFEST; echo MANIFEST) |
  sort | uniq -u | xargs -r rm

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

    
ответ дан pixelbeat 06.05.2010 в 18:17
  • Я получаю rm: отсутствующий операнд в вашей команде. Я просто вычислил это с помощью ls, comm и xargs. В любом случае спасибо pb –  brice 06.05.2010 в 18:22
  • Добавьте -r в xargs, чтобы удалить это предупреждение (когда файлы не нужны для удаления) –  pixelbeat 07.05.2010 в 04:11
  • Установить разницу с помощью grep вместо: find ./ -type f -printf "% P \ n" | fgrep -vf MANIFEST | ... –  Mark Edgar 10.05.2010 в 13:12
13

Для каждого файла в текущем каталоге grep имя файла в файле MANIFEST и rm файл , если он не сопоставлен.

for file in *
  do grep -q -F "$file" PATH_TO_YOUR_MANIFIST ||  rm "$file" 
done
    
ответ дан Jürgen Hötzel 06.05.2010 в 22:10
  • Если вы используете этот метод, обязательно добавьте имя файла манифеста в сам манифест, если вы помещаете его в тот же каталог, где вы удаляете файлы. Если вы поместите этот код в скрипт, добавьте имя этого скрипта в манифест. –  Ciske Boekelo 11.11.2013 в 17:38
3

понял это:

ls -1 > ALLFILES
comm -3 MANIFEST ALLFILES | xargs rm
    
ответ дан brice 06.05.2010 в 18:23
  • Да, comm -3 соответствует моему решению выше. Но будьте осторожны, поскольку комм ожидает уже отсортированных входов –  pixelbeat 06.05.2010 в 18:27
  • Приветствия, изъятые с использованием заданной разности несортированных. –  brice 06.05.2010 в 18:40
  • Используйте xargs -L 1, если ваши имена файлов содержат пробелы. –  djjeck 06.05.2014 в 23:23
1

Просто для удовольствия, Perl 1-liner ... в действительности не нужен, но гораздо более настраиваемый / расширяемый, чем Bash, если вам нужно что-то более приятное:)

$ ls
1   2   3   4   5   M
$ cat M
1
3
$ perl -e '{use File::Slurp; %M = map {chomp; $_ => 1} read_file("M"); $M{M}=1; \
foreach $f (glob("*")) {next if $M{$f}; unlink "$f"||die "Can not unlink: $!\n" };}' 
$ ls
1   3   M

Вышеуказанное может быть даже короче, если вы передадите манифест на STDIN

perl -e '{%M = map {chomp; $_ => 1} <>; $M{M}=1; \
foreach $f (glob("*")) {next if $M{$f};unlink "$f"||die "Can not unlink: $!\n" };}' M
    
ответ дан DVK 06.05.2010 в 18:46
0

Предполагается, что MANIFEST уже отсортирован:

find -type f -printf %P\n | sort | comm -3 MANIFEST - | xargs rm
    
ответ дан Dennis Williamson 06.05.2010 в 18:31