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

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

найти новейшие 3 файла просто:

ls -t | head -3

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

для этого я использую скрипты Debian Wheezy и bash.

7 ответов


в этом списке будут перечислены все файлы, кроме новейших трех:

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 вполне безопасно, тем более, если это сценарий только один раз.

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


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

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

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

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

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

Если вы хотите 1 вкладыш


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

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

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g | 
head -n -3 | 
cut -d $'\t' -f 2- |
xargs rm

объяснение:

find выводит список всех файлов (не каталогов) в текущей папке. Они распечатаны с временными метками.
sort сортирует строки на основе типа timestamp (старые сверху).
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 файлов с различными метками времени в текущей папке. Сначала запустите это и код для удаления, чтобы проверить код.


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

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

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

в zsh:

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

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

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

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


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

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-

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

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