Удалите все файлы, кроме новейших 3 в bash script

Вопрос: Как удалить все файлы в каталоге, кроме новейших 3?

Поиск новых трех файлов прост:

ls -t | head -3

Но мне нужно найти все файлы, кроме новейших 3-х файлов. Как это сделать и как удалить эти файлы в одной строке, не создавая для этого ненужный цикл?

Я использую сценарии Debian Wheezy и bash для этого.

Ответ 1

Здесь перечислены все файлы, кроме последних трех:

ls -t | tail -n +4

Это приведет к удалению этих файлов:

ls -t | tail -n +4 | xargs rm --

Здесь также будут перечислены dotfiles:

ls -At | tail -n +4

и удалить с помощью dotfiles:

ls -At | tail -n +4 | xargs rm --

Но будьте осторожны: разбор ls может быть опасным, если имена файлов содержат забавные символы, такие как символы новой строки или пробелы. Если вы уверены, что ваши имена файлов не содержат забавных символов, тогда синтаксический анализ ls вполне безопасен, тем более, если это только один раз script.

Если вы используете script для повторного использования, то вам, безусловно, не следует анализировать вывод ls и использовать описанные здесь методы: http://mywiki.wooledge.org/ParsingLs

Ответ 2

Ниже представлено несколько сложное, но очень осторожное, чтобы быть правильным, даже с необычными или намеренно злонамеренными именами файлов. К сожалению, для этого требуются инструменты GNU:

count=0
while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do
  (( ++count > 3 )) && printf '%s\0' "$filename"
done < <(find . -maxdepth 1 -type f -printf '%[email protected] %P\0' | sort -g -z) \
     | xargs -0 rm -f --

Объясняя, как это работает:

  • Найти emits <mtime> <filename><NUL> для каждого файла в текущем каталоге.
  • sort -g -z выполняет общий (с плавающей точкой, в отличие от целочисленного) числовой сортировки на основе первого столбца (раз) с линиями, разделенными NUL.
  • Первый read в цикле while отключает mtime (больше не требуется после завершения sort).
  • Второй read в цикле while читает имя файла (работает до NUL).
  • Цикл увеличивается, а затем проверяет счетчик; если состояние счетчика указывает, что мы прошли начальное пропущение, мы печатаем имя файла, ограниченное NUL.
  • xargs -0 затем добавляет это имя файла в список argv, который он собирает, для вызова rm с.

Ответ 3

ls -t | tail -n +4 | xargs -I {} rm {}

Если вам нужен 1 лайнер

Ответ 4

Решение без проблем с "ls" (файлы со странным именем)

Это сочетание ответа и анубхавы. Оба решения не работают для меня. Поскольку я искал сценарий, который должен запускаться каждый день для резервного копирования файлов в архиве, я хотел избежать проблем с ls (кто-то мог сохранить какой-нибудь смешной файл с именем в моей папке для резервных копий). Поэтому я изменил упомянутые решения в соответствии со своими потребностями. Решение Ceving удаляет три новейших файла - не то, что мне было нужно, и спросили.

Мое решение удаляет все файлы, кроме трех новейших файлов.

find . -type f -printf '%[email protected]\t%p\n' |
sort -t $'\t' -g | 
head -n -3 | 
cut -d $'\t' -f 2- |
xargs rm

Некоторое объяснение:

find списки всех файлов (не каталогов) в текущей папке. Они распечатываются с отметками времени.
sort сортирует строки по временной метке (самая старая сверху).
head печатает верхние строки, до последних 3 строк.
cut удаляет временные метки.
xargs запускает rm для каждого выбранного файла.

Для проверки моего решения:

(
touch -d "6 days ago" test_6_days_old
touch -d "7 days ago" test_7_days_old
touch -d "8 days ago" test_8_days_old
touch -d "9 days ago" test_9_days_old
touch -d "10 days ago" test_10_days_old
)

Это создает 5 файлов с разными временными метками в текущей папке. Сначала запустите этот скрипт, а затем код для удаления старых файлов.

Ответ 5

В зш:

rm /files/to/delete/*(Om[1,-4])

Если вы хотите включить точечные файлы, замените часть в скобках на (Om[1,-4]D).

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

Пояснение: круглые скобки содержат Glob Qualifiers. O означает "упорядочить по убыванию", m означает mtime (другие ключи сортировки см. В man zshexpn - большая страница man; поиск "быть отсортированным"). [1,-4] возвращает только совпадения с [1,-4] индексом 1 - (последний + 1 - 4) (обратите внимание на -4 для удаления всех, кроме 3).

Ответ 6

Не используйте ls -t, поскольку он небезопасен для имен файлов, которые могут содержать пробелы или специальные символы глобуса.

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

find . -maxdepth 1 -type f -printf '%[email protected]\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --

Ответ 7

ls -t | tail -n +4 | xargs -I {} rm {}

Майкл Баллент лучше всего работает как

ls -t | tail -n +4 | xargs rm --

выведите мне ошибку, если у меня меньше 3 файлов

Ответ 8

Вместо ls используется find с преобразованием Шварца..

find . -type f -printf '%[email protected]\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-

find выполняет поиск файлов и украшает их меткой времени и использует табулятор для разделения двух значений. sort разделяет входные данные табулятором и выполняет общую числовую сортировку, которая правильно сортирует числа с плавающей запятой. tail должен быть очевиден и cut undecorates.

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