Bash сравнить даты изменения файлов
У меня есть папка с кучей подпапок, эти папки asciidoctor отформатированы с .adoc расширением.
Каждый раз, когда я вносил изменения в файлы (что часто), мне нужно запустить
скомпилировать его в формат HTML.
Я пытаюсь автоматизировать процесс. до сих пор я пришел с этим с помощью entr :
но работает только с существующей папкой не для подпапок. Я пробовал этот вариант, но он не работает:
Любые идеи, как я мог бы реализовать этот процесс автоматизации для всех вложенных папок?
Linux предоставляет удобный интерфейс для мониторинга всех событий файловой системы, таких как создание, изменение, удаление файлов. Интерфейс представляет собой inotify семейство системных вызовов, утилиты пользовательского пространства, использующие эти вызовы, предоставляются inotify-tools пакетом в Ubuntu (доступно в репозитории юниверсов). Если у вас его еще нет, установите:
inotify-tools предоставляет inotifywait и inotifywatch двоичные файлы, нам нужен первый.
Таким образом, вы хотите выполнить команду, asciidoctor -q some_file когда какой-либо .adoc файл будет изменен ( some_file будет заменен этим), если, если это так, если ваши .adoc файлы находятся в каталоге /foo/bar , вы можете установить часы:
-q включает тихий режим, никакой информации от inotifywait себя
-m включает режим мониторинга, иначе он выйдет после первого события
--event modify , нас интересует только modify событие, то есть когда файл изменяется. Другие возможные значения включают open и close т. Д.
--format %w , мы хотим, чтобы имя файла было изменено, а не куча другой информации, так как мы будем использовать имя файла в качестве ввода для другой команды
/foo/bar/*.adoc будет расширен до всех .adoc файлов в /foo/bar каталоге
Теперь вышеприведенное покажет вам имя файла, когда что-либо будет изменено, теперь для запуска команды с именем файла (при условии, что команда принимает аргументы через STDIN):
Вы также можете установить рекурсивное наблюдение за каталогом, которое вам нужно будет использовать grep для фильтрации только нужных файлов. Здесь установка watch recursively ( -r ) на каталог /foo/bar и использование grep для фильтрации только .adoc файлов:
При просмотре каталогов спецификатор выходного формата %w разрешается в имя директории, поэтому нам нужно %f получить имя файла. При просмотре файлов %f разрешил бы пустую строку.
Обратите внимание, что вы также можете работать inotifywait в режиме daemon ( -d ), вы также можете создавать сценарии целиком и / или работать в фоновом режиме, и / или играть с другими дополнительными параметрами.
Кроме того, вы можете заменить asciidoctor любую другую команду по вашему выбору, если хотите.
Система РедХат 6
date +%m/%d/%Y
В man date есть пример с датой в том формате, в котором оно понимает: «2004-02-29 16:21:42».
И приведенный пример считает разницу в секундах, а не в месяцах.
А в месяцах можно считать двояко. Можно в секундах, затем делить на 30 дней:
Но, ИМХО, так не совсем правильно. Особенно ошибка будет заметна на больших диапазонах.
Я бы отдельно считал разницу в годах, отдельно в месяцах:
Kroz ★★★★★ ( 31.12.15 14:47:17 )
Последнее исправление: Kroz 31.12.15 14:48:01 (всего исправлений: 1)
Переводить в Epoch, разность делить до нужной точности.
А зачем вообще все эти date и прочие сложности? Количество месяцев в любом году же, вроде бы, постоянно, не?
Необходимо получить разницу в количестве месяцев между двумя датами вида dd/mm/yyyy
А скорость получения важна? :-)
Или я задачу не понял? Судя по тому, как тут все ее серьезно обсуждают, это весьма возможно.
Zmicier ★★★★★ ( 31.12.15 16:36:45 )
Последнее исправление: Zmicier 31.12.15 16:39:05 (всего исправлений: 1)
bash -c «python -c \„import datetime;. \“»
Если (текущая дата - дата сертификата из токена > 14 месяцев) то слать емыл админу что в сервере hostname срок действия сертификата, через месяц закончится. иначе Если (текущая дата - дата сертификата из токена > 15 месяцев) то слать емыл админу что в сервере hostname срок действия сертификата уж кончился.
Скрипт засовывается в крон, и раз в день исполняется. Цель всего, заблаговременно понять что сертификат скоро кончится и нужно его перевыпустить.
Собственно весь код «скрипта» готов, только последняя часть расчета разницы в датах всё застопорило. Предполагал что «date -d» можно передать дату/время в нужном мне формате (dd/mm/yyyy), а оказывается оно понимает только один определенный вид указанный в man. Решение задачи будет приведение даты в тот вид который надо команде date, точность расчета +/- день роли особой не играет.
Я создаю общую систему компиляции / транспиляции. Один из способов узнать, был ли файл уже скомпилирован / перенесен, – это сравнить даты изменения файла источника и целевого файла.
Мне нужно написать сценарий bash, который может это сделать:
но как я могу извлечь даты из выхода stat и сравнить их? Есть ли лучший способ, чем stat для сравнения последнего времени модификации файла?
Если я вызову stat в файле журнала, я получаю следующее:
AFAICT, временная гранулярность не более тонкая, чем секунды. Мне нужно получить что-то более зернистое, чем это возможно.
Учитывая, что вы используете stat (аналогичная функциональность, но другой формат вывода на BSD и GNU), вы также можете использовать test утилиту, которая напрямую выполняет это сравнение:
В вашем примере,
Эта функция недоступна в POSIX (см. Ее документацию для test ), которая дает в качестве обоснования:
Это может измениться в будущем, хотя функция широко поддерживается.
Обратите внимание, что когда операнды являются символическими ссылками, это время модификации целевой символической ссылки, которая рассматривается (как правило, вы хотите, используйте find -newer а если нет). Когда символические ссылки не могут быть разрешены, поведение между реализациями (некоторые считают, что существующий файл всегда новее, чем тот, который не может быть разрешен, некоторые всегда будут сообщать false, если какой-либо из операндов не может быть разрешен).
Также обратите внимание, что не все реализации поддерживают субсекундную детализацию ( test bash 's / [ встроенный с версии 4.4 по-прежнему не выполняется, например, test GNU и встроенный test zsh или ksh93 , по крайней мере, на GNU / Linux).
- Для реализации утилиты test GNU (хотя обратите внимание, что ваша оболочка, если fish или Bourne-like, также будет иметь test / [ встроенный, который обычно меняет его, используйте env test вместо test чтобы обойти его), get_mtime в test.c читает struct timespec и
- option -nt использует эти данные
При тестировании на этой Linux-системе. Обычным способом проверки времени файла является оболочка:
Кажется, работает с секундами. Это, которое коснется файлов с разницей времени менее секунды, не обнаружит эту разницу:
Чтобы подтвердить проблему (время после точки составляет наносекунды):
file1 (бит) более новый, чем file2 .
Теперь проблема заключается в правильной обработке значения времени.
Одним из решений является использование форматированного вывода ls:
Извлечение времени на две переменные (без точки):
И сравните время (раз, когда наносекунды едва ли соответствуют 64-битовому значению. Если ваша система не использует 64 бит, это сравнение не удастся):
Это показывает, что file1 более новый, чем file2
Если ls не имеет необходимого формата, вы можете попробовать stat.
Если выход показывает наносекунды, нам понадобится дата для синтаксического анализа (и форматирования) времени.
Остальное одно и то же, присвойте результаты file1 и file2 двум переменным и численно сравните их.
Если вы захотите принять не встроенный Linux, вы можете использовать test внешнюю команду, которая является частью GNU coreutils. ( test – другое имя для [ и является встроенным в большинство оболочек). Он имеет наносекундную детализацию (вплоть до точности, сообщаемой файловой системой).
Оператор -nt не определяется POSIX, но он присутствует во многих реализациях, включая тесты дефиса, bash, pdksh, mksh, ATT ksh, zsh, GNU coreutils и BusyBox. Однако многие реализации (dash, bash, pdksh, mksh, BusyBox – протестированы на Debian jessie) поддерживают только 1-секундную детализацию.
Но было бы лучше использовать инструменты, предназначенные для этой работы, такие как make . Выполнение команды только в том случае, если определенный файл является более новым, чем какой-либо другой файл, является всей точкой make. Со следующим содержимым в файле Makefile (обратите внимание, что перед каждой командной строки вам нужен символ табуляции).
Запустите make target чтобы выполнить команды, которые его генерируют. Если target существует и является более новой, чем source , команды не выполняются. Прочтите дополнительную документацию по make для получения дополнительной информации.
POSIXly, вы бы использовали find :
Для символических ссылок, которые сравнивают mtime самих символических ссылок. Чтобы сравнить цели символических ссылок, добавьте параметр -H или -L .
Это предполагает, что $source_file не начинается с - и в противном случае не соответствует одному из предикатов find . Если вам нужно иметь дело с произвольными именами файлов, вам сначала нужно сделать такие вещи:
GNU и FreeBSD find реализации, по крайней мере, поддерживают субсекундную детализацию. AFAICT, macos, похоже, даже не сохраняет информацию о второстепенном времени в атрибутах файла в файловой системе HFS +.
Вот пример того, как я хотел бы использовать это, хотя он не работает как есть:
Как я могу достичь желаемого результата?
Правильный ответ по-прежнему отсутствует:
Вам не хватает формата даты для сравнения:
Вам также не хватает структур цикла, как вы планируете получать больше дат?
Можно использовать стандартное сравнение строк для сравнения хронологического упорядочения [строк в формате года, месяца, дня].
К счастью, когда [строки, которые используют формат YYYY-MM-DD] сортируются * в алфавитном порядке, они также сортируются * в хронологическом порядке.
(* – сортировка или сравнение)
В этом случае ничего не нужно. ура!
Это не проблема циклических структур, а типов данных.
Эти даты ( todate и cond ) являются строками, а не цифрами, поэтому вы не можете использовать оператор test «-ge». (Помните, что квадратичная нотация эквивалентна командному test ).
Вы можете использовать разные обозначения для своих дат, чтобы они были целыми числами. Например:
будет генерировать целое число, например, 20130715 на 15 июля 2013 года. Затем вы можете сравнить свои даты с «-ge» и эквивалентными операторами.
Обновление: если даны даты (например, вы читаете их из файла в формате 2013-07-13), тогда вы можете легко их обрабатывать с помощью tr.
Оператор -ge работает только с целыми числами, которых нет у ваших дат.
В любой оболочке вы можете преобразовать строки в числа, соблюдая порядок дат, просто удалив тире.
Кроме того, вы можете пойти традиционным и использовать утилиту expr .
Поскольку вызовы подпроцессов в цикле могут быть медленными, вы можете предпочесть сделать преобразование, используя конструкторы обработки строкой оболочки.
Конечно, если вы можете получить даты без дефиса в первую очередь, вы сможете сравнить их с -ge .
Я конвертирую строки в unix-timestamps (секунды с 1.1.1970 0: 0: 0). Они легко сравниваются
даты – это строки, а не целые числа; вы не можете сравнивать их со стандартными арифметическими операторами.
один подход, который вы можете использовать, если гарантированно будет разделитель - :
Это работает еще в bash 2.05b.0(1)-release .
Эти функции являются выдержкой из скрипта в этом потоке!
Применение
Вы можете также использовать встроенную функцию mysql для сравнения дат. Это дает результат в «дни».
Просто вставьте значения переменных $DBUSER и $DBPASSWORD соответствии с вашими.
конкретный ответ bash
Поскольку мне нравится уменьшать вилки и bash , разрешите много трюков, есть моя цель:
Это приведет к повторному заполнению обеих переменных $todate и $cond , используя только одну вилку, с выводом date -f - принятия stdio для чтения по одной дате за строкой.
Наконец, вы можете разбить свою петлю с помощью
Или как функция :
Использование встроенного printf bash, который мог бы отображать время даты с секундами от эпохи (см. man bash 😉
В этом скрипте используется только одна вилка.
FWIW: на Mac, кажется, что подача только даты типа «2017-05-05» в дату добавит текущее время к дате, и вы получите различную ценность каждый раз, когда вы конвертируете ее в эпоху. для получения более согласованного времени времени для фиксированных дат, включают фиктивные значения в течение часов, минут и секунд:
Это может быть странность, ограниченная версией даты, поставляемой с macOS …. проверена на macOS 10.12.6.
Вот пример того, как я хотел бы использовать это, хотя это не работает как есть:
Как мне достичь желаемого результата?
Правильный ответ все еще отсутствует:
Не знаю, почему кто-то опроверг это, он довольно точен и не связан с объединением некрасивых строк. Преобразуйте дату в метку времени Unix (в секундах), сравните метки времени Unix.
Я думаю, для меня главное преимущество этого решения в том, что вы можете легко делать сложения или вычитания. Например, я хотел, чтобы время ожидания составляло x секунд, но моя первая идея ( timeout=$(`date +%Y%m%d%H%M%S` + 500) ) явно неверна.
Вам не хватает формата даты для сравнения:
Вам тоже не хватает циклических структур, как вы планируете получать больше дат?
date -d не является стандартным и не работает на типичной UNIX. На BSD он даже пытается установить значение кенеля DST .
Можно использовать стандартное сравнение строк для сравнения хронологического порядка [строк в формате год, месяц, день].
К счастью, когда [строки, которые используют формат YYYY-MM-DD] сортируются * в алфавитном порядке, они также сортируются * в хронологическом порядке.
(* - отсортировано или сравнено)
Ничего особенного в этом деле не нужно. ура!
Это проще, чем мое решение if [ $(sed -e s/-//g
Это проблема не циклических структур, а типов данных.
Эти даты ( todate и cond ) являются строками, а не числами, поэтому вы не можете использовать оператор "-ge" для test . (Помните, что обозначение в квадратных скобках эквивалентно команде test .)
Что вы можете сделать, это использовать другую запись для ваших дат, чтобы они были целыми числами. Например:
выдаст целое число, например 20130715, 15 июля 2013 г. Затем вы сможете сравнить свои даты с "-ge" и эквивалентными операторами.
Обновление: если указаны ваши даты (например, вы читаете их из файла в формате 2013-07-13), то вы можете легко предварительно обработать их с помощью tr.
Оператор -ge работает только с целыми числами, которых нет у ваших дат.
В любой оболочке вы можете преобразовать строки в числа, соблюдая порядок дат, просто удалив тире.
Кроме того, вы можете перейти на традиционные и использовать expr утилиту.
Поскольку запуск подпроцессов в цикле может быть медленным, вы можете предпочесть выполнить преобразование, используя конструкции обработки строки оболочки.
Конечно, если вы можете получить даты без дефисов, вы сможете их сравнить -ge .
Я конвертирую строки в метки времени Unix (секунды с 1.1.1970 0: 0: 0). Это можно легко сравнить
Читайте также: