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

6

Каков наилучший способ удалить все файлы в текущем каталоге с некоторым префиксом, кроме файла с этим префиксом, но имеющего наибольший размер среди всех файлов с этим префиксом?

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

Например, текущий каталог содержит следующие файлы:

-rw-rw----  1 user user 3468 Jan 01 00:00 filea
-rw-rw----  1 user user 3434 Jan 01 00:00 pre_0
-rw-rw-r--  1 user user 9769 Jan 01 00:00 fileb
-rw-rw-r--  1 user user 1950 Jan 01 00:00 filec
-rw-rw-r--  1 user user 8654 Jan 01 00:00 pre_1
-rw-rw----  1 user user 6508 Jan 01 00:00 pre_2

После запуска команды или сценария для удаления всех файлов с префиксом «pre_», кроме самого большого, текущий каталог должен быть указан как:

-rw-rw----  1 user user 3468 Jan 01 00:00 filea
-rw-rw-r--  1 user user 9769 Jan 01 00:00 fileb
-rw-rw-r--  1 user user 1950 Jan 01 00:00 filec
-rw-rw-r--  1 user user 8654 Jan 01 00:00 pre_1
Д. Чен
источник
2
Мне просто интересно, что такое реальное приложение для этого? Это управление файлами журналов или файлами в фотогалерее, размер которых был изменен на множество разных размеров (и теперь вы хотите удалить файлы меньшего размера), или что-то еще?
Кусалананда
@Kusalananda Да, приложение в моем случае - это управление файлами журналов и записей. Другое упомянутое вами приложение по управлению фотогалереей также очень интересно.
Д. Чен

Ответы:

7

Вы можете использовать комбинацию из нескольких утилит:

stat -c '%s %n' pre_* | sort -k1,1rn | tail -n +2 | cut -d' ' -f2 | xargs rm

Предполагая систему GNU и никаких необычных имен файлов.

  • statполучает размер файла и имя, разделенное пробелом для всех pre_*файлов

  • sort сортирует файл по размеру файла, при этом самый высокий размер идет вверх

  • tail -n +2 получает остальные файлы отдельно от максимального размера

  • cut -d' ' -f2получает только имя файла, а rm( xargs rm) выполняет удаление

heemayl
источник
1
Не собирается работать с именами файлов с пробелами. Сломался бы на стадии cut. По крайней мере, эта стадия может быть исправлена, если cutвызов заменен на sed 's@^[^ ]\+ @@'. Не уверен, что xargsбудет работать правильно.
Руслан
@Ruslan Это было бы сломано на statстадии тогда, поэтому я не упомянул необычные имена файлов
heemayl
Почему? Разве оболочка не распространяется на кавычки / экранированные имена?
Руслан
statне может отправить вывод, как NUL отделены, вот почему ..
Heemayl
Ну, я понимаю, что перевод строки в имени файла необычен, но почему вы предполагаете, что пробел необычен?
Руслан
7

С zsh:

rm -f pre*(OL[2,-1])
  • OL: обратный порядок по размеру
  • [2,-1]только второй

Эквивалент bashутилиты with и GNU будет выглядеть примерно так:

eval "files=($(LC_ALL=C ls --quoting-style=shell-always -dS ./pre*))"
rm -f "${files[@]:1}"

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

rm -f pre*(.OL[2,-1])

(нет прямого bash + GNU эквивалент). Вы можете захотеть включить символические ссылки в обычные файлы и рассмотреть размер цели символических ссылок:

rm -f pre*(-.OL[2,-1])

С помощью lsдобавьте -Lопцию, чтобы рассмотреть размер целей символических ссылок.

Стефан Шазелас
источник
Ух ты, может быть, действительно есть что-то, что zsh... Я до сих пор не научился этому. Также не нашли хорошей отправной точки.
Wildcard
1
@ Дикая карта, конечно, есть :-). Вы можете начать с Руководства пользователя .
Стефан Шазелас