Гость
Зарегистрироваться
Войти
Simant
Статьи
Новости
Где я?
Блог

© Дарислав



Моя музыка:
  • Группа ЧТД


  • Мои аккаунты:

    Аудиокниги:
    (моим голосом)

    Полезные ссылки:

     


    Скачать

    Яндекс.Метрика
    Яндекс цитирования



    Премудрости linux shell. Часть 1.

    Привет всем!

    Копаясь в хелпах ОС Linux в поисках нужных механизмов, решил написать серию обзоров основных пригодившихся мне команд. Эти материалы расчитаны в первую очередь на новичков в Linux, желающих постичь выше означенный сабж. Но я надеюсь, что и любители с профессионалами, знающие Linux вдоль и поперек, найдут здесь что-нибудь полезное, так как материал пишется применительно к решению реальных насущных задач админа.

    И начну я собственно, с того, на чем завис недавно и надолго. С некоторых пор на моем сайте есть раздел файлы, который представляет из себя самодельный "автоиндекс", отображающий содержимое определенной папки на диске. Захотелось мне внести этот раздел в Sitemap сайта, чтобы поисковики вовремя реагировали на появившиеся новинки. Ну, внести-то оно легко. А вот как для ряда основных папок вывести актуальную дату последнего изменения? Ведь дата последнего изменения конкретной папки не меняется, если изменения внесены где-то глубоко в подпапках.

    К вопросу о том, нафига так извращаться, когда можно просто указать скажем, периодичность "weekly" и не париться вообще. Ну будут яндекс с гуглем раз в неделю копаться в папках и пёс с ними, пусть себе копаются. Тут несколько доводов сразу. Во-первых, многие разделы не обновляются годами, поэтому я не вижу смысла напрягать поисковых роботов и свой сервер лишней работой. Во вторых, если в таком разделе, например, указать периодичность "yearly", то робот целый год про него не вспомнит. А если там вдруг появилось изменение? Так же бывает иногда. Надо же как-то об этом сообщить... В-третьих, есть разделы, которые обновляются довольно часто, но иногда случаются периоды затишья на несколько месяцев. Опять-таки, простое указание более короткого интервала в период затишья будет излишне напрягать роботов и мой сервер. Не то чтобы я опасаюсь падения своего сервера или даже поискового робота из-за такой мелочи. Просто нафига гонять туда-сюда объективно лишний трафик?

    Итак, задача - просканировать рекурсивно конкретную папку, вывести LastModified для всех найденных элементов, полученный список отсортировать и взять последнюю строку. Казалось бы, задача непростая. Однако же, на то она и Linux, что любая, даже кажущаяся сложной, задача по обработке файлов в ней как правило решается одной строкой.

    Есть такая команда find. Она предназначена для поиска файлов по множеству разнооборазных критериев (время создания, время последнего изменения, время последнего доступа к файлу, атрибуты "executable" (запускаемый), "empty" (пустой) и многие другие) и выполнения различных действий с найденными файлами. Среди этих действий, конечно же есть простой вывод.

    # find /pub/ -print
    /pub/Distrib/
    /pub/Multimedia/
    ...

    Для тех, кто не знаком с премудростями коммандной строки Linux, есть аналогичный ключ для построчного вывода в файл:

    # find /pub/ -fprint /path/to/file

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

    # find /pub/ -print > /path/to/file

    Знак > в данном случае означает записать в файл справа от знака ">" вывод (практически любой) команды слева от него. Необходимо отметить, что такой вывод полностью сотрет содержимое указанного для вывода файла, если оно было. Если же такого файла еще нет, он будет создан. Но есть и способ дополнить файл, не стирая его содержимое. Вот он:

    # find /pub/ -print >> /path/to/file

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

    Новичкам предлагаю поэкспериментировать с этими механизмами. Создайте экспериментальныю папку, например "~/tests/" и потренируйтесь:

    # mkdir ~/tests
    # cd ~/tests
    # ls / > test1
    # find /bin/ > test2

    итд...

    Но вернемся к команде find. У нее есть более полезный в нашем случае ключ вывода в указаном формате - -printf. Например:

    # find /pub/ -printf "%p\n"
    /pub/Distrib/
    /pub/Multimedia/
    ...

    Вывод в данном случае полностью совпадет с приведенным ранее, так как формат "%p\n" является форматом для ключа -print. Нам же необходимо вместо имени файла вывести время его последнего изменения. Для этого есть ключ %T и целый ряд параметров к нему. Рассмотрим те, которые нам понадобятся.

    Y - год полностью;

    m - месяц двузначным числом [01..12];

    d - день месяца в формате [01..31];

    H - часы [00..23];

    M - минуты [00..59];

    S - секунды и миллисекунды [00.00..61.00].

    Замечу, что это не моя опечатка по поводу 61 секунды. Так написано в мануале. Кому интересно, посмотрите сами:

    # man find

    Кстати, тут же Вы найдете полный список ключей и опций к find. В моей Ubuntu 12.04 этот мануал на английском. Возможно, вам повезет  в Вашей Linux этот мануал будет на русском.

    Итак, для корректной сортировки, формат вывода даты и времени последнего изменения для нашего случая будет таким:

    # find /pub/ -printf "%TY.%Tm.%Td %TH:%TM:%TS\n"
    2008.01.07 01:05:22.0000000000
    2006.05.11 17:27:37.0000000000
    ...

    Теперь у нас есть полный список дат последнего изменения всех файлов (и папок) из интересующей нас папки. Нужно его как-то отсортировать. Для этого етсь команда sort. Но сначала лирическое отступление для новичков.

    Есть еще одна великая вещь в командной строке Linux. Это символ "|". Он позволяет объединить несколько команд, выполняемых последовательно, с передачей вывода друг другу. Например:

    # find /pub/ -printf "%TY.%Tm.%Td %TH:%TM:%TS\n" | sort

    Сначала команда find сформирует уже известный нам список дат. Затем символ "|" передаст этот список команде sort, которая в свою очередь этот список отсортирует, а потом уже выведет на экран.

    В качестве эксперимента рекомендую поиграться с командой grep, которая выполняет роль фильтра. Например

    # find /pub/ -printf "%TY.%Tm.%Td $TH:%TM:%TS\n" | grep 2012

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

    Вернемся к нашим баранам. Точнее, датам. Все они нам не нужны, только самая последняя. Для выбора последних строк есть команда tail. Сама по себе без параметров она выводит 10 последних строк из всех полученных для обработки. Для вывода только одной строки есть ключ -1. Итак:

    # find /pub/ -printf "%TY.%Tm.%Td %TH:%TM:%TS\n" | sort | tail -1
    2012.10.28 20:25:22.0000000000

    Мы получили дату последнего изменения самого нового файла в стрктуре папки /pub/. Осталось только немного подредактировать формат даты под стандарт протокола Sitemaps - W3C DateTime.

    # find /pub/ -printf "%TY.%Tm.%Td%%TH:%TM+03:00\n" | sort | tail -1
    2012.10.28T20:25+03:00

    Ну а дальше, как вам удобнее. Можно вписать саму комманду в функцию shell_exec() в PHP, не забыв подставить нужный путь, а можно обернуть ее в отдельный скрипт для удобства.

    # echo '#!/bin/sh' > /var/www/php/sh/lastmod
    # echo 'find $1 -printf "%TY.%Tm.%Td%%TH:%TM+03:00\n" | sort | tail -1' >> /var/www/php/sh/lastmod

    Теперь можно писать везде и всегда что-то типа

    # /var/www/php/sh/lastmod /path/to/directory

    И получать заветную дату. В случае, если вдруг придется изменить формат вывода, достаточно будет изменить одну строку в скрипте, а не множество строк в PHP: мы ведь собираемся использовать этот приём для множества разных папок, и не факт, что только в одном PHP скрипте.

    Что ж, позвольте откланяться. Поставленная задача достигнута!

    Удачи!

    Дата публикации: 2012-10-28 20:11:33

    © 2007-2017, Simant