Как мне написать скрипт для перемещения только 20 самых старых файлов из одной папки в другую? Есть ли способ получить самые старые файлы в папке?
bash
shell
shell-script
files
timestamps
user11598
источник
источник
atime
(последний доступ),ctime
(последнее изменение разрешения) иmtime
(последнее изменение) ... например.ls -t
и ФАЙНДprintf "%T"
использованиеmtime
... Кажется, по этой ссылке , чтобы моиext4
перегородки способны обрабатывать дату создания, ноls
иfind
иstat
не соответствующие параметры (пока) ...Ответы:
Синтаксический вывод
ls
является не надежным .Вместо этого используйте,
find
чтобы найти файлы иsort
упорядочить их по метке времени. Например:Что все это делает?
Сначала
find
команды находят все файлы и каталоги в текущем каталоге (.
), но не в подкаталогах текущего каталога (-maxdepth 1
), затем распечатывают:Отметка времени важна. Спецификатор
%T@
формата для-printf
разбивки наT
, который указывает «Время последнего изменения» файла (mtime) и@
, который указывает «Секунды с 1970 года», включая доли секунды.Пространство - это просто произвольный разделитель. Полный путь к файлу таков, что мы можем обратиться к нему позже, и символ NULL является терминатором, поскольку он является недопустимым символом в имени файла и, таким образом, позволяет нам точно знать, что мы достигли конца пути к файл.
Я включил
2>/dev/null
так, что файлы, к которым у пользователя нет прав доступа, исключаются, но сообщения об ошибках об их исключении исключаются.Результатом
find
команды является список всех каталогов в текущем каталоге. Список передается по трубопроводу,sort
которому поручено:-z
Обрабатывайте NULL как символ конца строки вместо новой строки.-n
Сортировать численноТак как секунды с 1970 года всегда идут вверх, мы хотим файл, метка времени которого была наименьшим числом. Первым результатом
sort
будет строка, содержащая метку времени с наименьшим номером. Осталось только извлечь имя файла.Результаты
find
,sort
трубопровод проходит через подмены процесса вwhile
котором он читается , как если бы это был файл на стандартный ввод.while
в свою очередь вызываетread
для обработки ввода.В контексте
read
мы устанавливаемIFS
переменную в ничего, что означает, что пробел не будет неправильно интерпретироваться как разделитель.read
сказано-r
, что блокирует расширение побега, и-d $'\0'
, что делает конец-строки разделителя NULL, соответствующий вывод из нашегоfind
,sort
трубопровода.Первый фрагмент данных, представляющий самый старый путь к файлу, которому предшествуют его временная метка и пробел, считывается в переменную
line
. Далее, подстановка параметров используется с выражением#*
, которое просто заменяет все символы от начала строки до первого пробела, включая пробел, ничем. Это удаляет метку времени модификации, оставляя только полный путь к файлу.На этом этапе имя файла сохраняется,
$file
и вы можете делать с ним все что угодно. Когда вы закончили делать что - то с$file
вwhile
цикл будет заявление иread
команда будет выполнена снова, извлекая следующий фрагмент и следующее имя файла.Есть ли более простой способ?
Нет. Более простые способы глючат.
Если вы используете
ls -t
и передаете по трубопроводуhead
илиtail
(или что-нибудь еще ), вы сломаете файлы с символами новой строки в именах файлов. Если у вас естьmv $(anything)
файлы с пробелами в имени, это приведет к поломке. Если выmv "$(anything)"
затем файлы с завершающими символами новой строки в имени, это приведет к поломке. Если вы этогоread
не-d $'\0'
сделаете, вы будете использовать файлы с пробелами в именах.Возможно, в определенных случаях вы точно знаете, что более простой способ достаточен, но вы никогда не должны записывать подобные предположения в сценарии, если вы можете избежать этого.
Решение
Звоните как:
Чтобы переместить самые старые 20 файлов из
/var/log/foo/
в/mnt/backup/
.Обратите внимание, что я включаю файлы и каталоги. Для файлов только добавить
-type f
кfind
вызову.Благодарность
Спасибо энзотибу и Павлу Танкову за улучшения этого ответа.
источник
-n
. По крайней мере, в моей версии он не сортирует десятичные числа правильно. Вы должны либо удалить точку в дате, либо использовать-printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz
дату ISO или что-то еще..
должна быть неуместна для вас). Было бы яснее сказатьsort -z -n -t. -k1
.%TS
также отображается «дробная часть», которая будет в форме00.0000000000
, поэтому вы также потеряете детализацию. Недавние GNUsort
могли решить эту проблему, используя-V
«сортировку версий», которая будет обрабатывать этот тип с плавающей запятой, как и ожидалось.%T@
также будет работать, потому что она дополняется нулями.Это самый простой в Zsh, где вы можете использовать
Om
Глоб классификатор для сортировки матчей по дате (сначала старые) и[1,20]
классификатором сохранить только первые 20 матчей:Добавьте
D
классификатор, если вы хотите также включить точечные файлы. Добавьте,.
если вы хотите сопоставлять только обычные файлы, а не каталоги.Если у вас нет zsh, вот Perl с одной строкой (вы можете сделать это менее чем за 80 символов, но с дополнительными затратами для ясности):
С помощью только инструментов POSIX или даже bash или ksh сортировка файлов по дате становится проблемой. Вы можете легко это сделать
ls
, но анализ выходных данныхls
проблематичен, так что это работает только в том случае, если имена файлов содержат только печатаемые символы, кроме символов новой строки.источник
Объединить
ls -t
вывод сtail
илиhead
.Простой пример, который работает, только если все имена файлов содержат только печатаемые символы, кроме пробелов и
\[*?
:источник
ls -1Atr
touch $'foo\n*'
. Что произойдет, если вы выполните mv "$ (ls)" с этим файлом?Вы можете использовать GNU find для этого:
Если find печатает время изменения (в секундах с 1970 года) и имя каждого файла текущего каталога, выходные данные сортируются по первому полю, 20 самых старых фильтруются и перемещаются в
dest_dir
. Удалите,echo
если вы проверили командную строку.источник
Никто (пока) не опубликовал пример bash, который обслуживает встроенные символы новой строки (вложенные что угодно) в имени файла, так что вот один. Перемещает 3 самых старых (mdate) обычных файла
Это фрагмент тестовых данных
Вот фрагмент проверки результатов
источник
Проще всего это сделать с GNU
find
. Я использую его каждый день на своем Linux DVR для удаления записей из моей системы видеонаблюдения старше одного дня.Вот синтаксис:
Помните, что
find
день определяется как 24 часа с момента исполнения. Поэтому файлы, которые в последний раз были изменены в 23:00, не будут удалены в 1:00.Вы даже можете комбинировать
find
с нимиcron
, поэтому удаление можно запланировать автоматически, выполнив следующую команду от имени пользователя root:Вы всегда можете получить больше информации
find
, обратившись к странице справочника:источник
так как другие ответы не соответствуют моим целям и задачам, эта оболочка протестирована на CentOS 7:
источник