Удалить все файлы, кроме 3 самых новых, в bash-скрипте
Вопрос: Как удалить все файлы в директории, за исключением трех самых новых?
Найти три самых новых файла довольно просто:
ls -t | head -3
Но мне нужно найти все файлы, кроме этих трех самых новых. Как это сделать и удалить эти файлы в одной команде, без использования ненужного цикла for
?
Я использую Debian Wheezy и bash-скрипты для этой задачи.
5 ответ(ов)
Этот код выведет список всех файлов, кроме трех новейших:
ls -t | tail -n +4
А этот код удалит эти файлы:
ls -t | tail -n +4 | xargs rm --
Стоит отметить, что этот подход не удаляет скрытые файлы (dotfiles). Если вы хотите также удалить скрытые файлы, замените ls -t
на ls -At
.
Двойной дефис (--
) после команды rm
является защитой от имен файлов, начинающихся с дефиса. Более подробную информацию можно найти здесь: https://unix.stackexchange.com/questions/1519/how-do-i-delete-a-file-whose-name-begins-with-hyphen-a-k-a-dash-or-minus.
Однако, имейте в виду, что эта команда может завершиться неудачей, если имена файлов содержат пробелы, переносы строк или другие необычные символы. Если ваши имена файлов могут содержать пробелы, или если вы планируете использовать этот код в скрипте, обязательно ознакомьтесь с этими статьями: http://mywiki.wooledge.org/ParsingLs и http://mywiki.wooledge.org/BashFAQ/003.
Решение без проблем с "ls" (файлы со странными именами)
Это комбинация ответов ceving и anubhava. Оба решения не работали для меня, потому что я искал скрипт, который должен запускаться каждый день для резервного копирования файлов в архив, и хотел избежать проблем с ls
(кто-то мог сохранить файл со смешным именем в моей папке для резервного копирования). Поэтому я изменил упомянутые решения, чтобы они соответствовали моим нуждам.
Мое решение удаляет все файлы, кроме трех самых новых.
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs -r rm
Немного объяснений:
find
перечисляет все файлы (исключая директории) в текущей папке. Они выводятся с отметками времени.sort
сортирует строки по отметкам времени (самые старые вверху).head
выводит строки, вплоть до последних 3-х.cut
удаляет отметки времени.xargs
выполняетrm
для каждого выбранного файла, причем-r
позволяет не выдавать ошибку, если файлы не найдены.
Для проверки моего решения выполните следующий код:
(
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 файлов с разными отметками времени в текущей папке. Сначала выполните этот скрипт, а затем код для удаления старых файлов.
Этот фрагмент кода действительно выглядит немного сложно, но он очень аккуратно подтверждает свою корректность, даже с необычными или намеренно вредоносными именами файлов. К сожалению, он требует 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 '%T@ %P\0' | sort -g -z) \
| xargs -0 rm -f --
Давайте разберем, как это работает:
- Команда
find
выводит<mtime> <filename><NUL>
для каждого файла в текущем каталоге. sort -g -z
выполняет общее (с плавающей точкой, в отличие от целочисленного) числовое сортирование на основе первого столбца (времени) с разделением строк по символу NUL.- Первый
read
в циклеwhile
удаляет время модификации (которое больше не нужно после сортировки). - Второй
read
в циклеwhile
считывает имя файла (продолжая до символа NUL). - Цикл увеличивает и проверяет счетчик; если состояние счетчика указывает на то, что мы уже пропустили первоначальные файлы, то мы выводим имя файла, разделенное NUL.
xargs -0
затем добавляет это имя файла в список аргументов, который он собирает для вызоваrm
.
Таким образом, данный код позволяет безопасно удалить файлы, игнорируя первые три из них, включая обработку имен файлов, которые могут содержать специальные символы или пробелы.
Если вам нужно удалить все файлы в текущем каталоге, кроме трех самых новых, вы можете использовать следующую однострочную команду в терминале:
ls -t | tail -n +4 | xargs -I {} rm {}
Эта команда работает следующим образом:
ls -t
— выводит список файлов, отсортированных по времени изменения, начиная с самых новых.tail -n +4
— пропускает первые три строки (т.е. самые новые файлы) и выводит оставшиеся.xargs -I {}
— принимает каждый файл из списка и выполняет командуrm {}
, удаляя их.
Таким образом, вы удалите все файлы, кроме трех самых новых. Будьте осторожны с этой командой, так как она удаляет файлы без возможности их восстановления.
Не используйте ls -t
, так как это небезопасно для имен файлов, которые могут содержать пробелы или специальные символы подстановки.
Вы можете воспользоваться утилитами на основе gnu
, чтобы удалить все, кроме трех самых новых файлов в текущем каталоге:
find . -maxdepth 1 -type f -printf '%T@\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --
Давайте разберем эту команду:
find . -maxdepth 1 -type f -printf '%T@\t%p\0'
— находит все файлы в текущем каталоге и выводит время их последнего изменения (в секундах с начала эпохи) и имя каждого файла, разделяя их нулевыми символами.sort -z -nrk1
— сортирует полученные файлы по времени изменения в порядке убывания (новейшие сначала), используя нулевые символы в качестве разделителей.tail -z -n +4
— пропускает три самых новых файла и выводит остальные, начиная с четвертого.cut -z -f2-
— извлекает только имя файла, оставляя таймстемпы.xargs -0 rm -f --
— принимает список имен файлов и удаляет их без подтверждения.
Таким образом, этот набор команд позволяет корректно и безопасно удалить лишние файлы, учитывая особенности именования.
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?
Как использовать 'grep' для непрерывного потока?
Как создать файл в Linux из терминала? [закрыто]
Автоматический вход в Docker через Bash-скрипт