В закладочках нашёл любопытный сервис, который очень полезен линуксоидам - конструктор для консольной команды FIND. Это такая типичная линуксовая утилита, у которой 100500 параметров и возможностей, ключи которой невозможно запомнить раз и навсегда. У меня огромная шпаргалка по find на все случаи жизни, чтобы не приходилось заново вспоминать, как реализовать тот или иной поиск.
Кое-что необычное по find уже публиковал на канале:
- очистка старых файлов
- поиск дубликатов файлов
- утилита fd для упрощения поиска через find
Сервис называется find-command-generator. С его помощью узнал, что find очень просто может находить файлы, которые принадлежат несуществующему пользователю или группе, или обоим одновременно. Бывает нужно такие найти:
Программисты любят ставить 777 без разбора. Постоянно с этим сталкиваюсь. Когда у них что-то работает не так, они первым делом права доступа 777 ставят, а потом дальше разбираются.
#bash #terminal #find
Кое-что необычное по find уже публиковал на канале:
- очистка старых файлов
- поиск дубликатов файлов
- утилита fd для упрощения поиска через find
Сервис называется find-command-generator. С его помощью узнал, что find очень просто может находить файлы, которые принадлежат несуществующему пользователю или группе, или обоим одновременно. Бывает нужно такие найти:
# find . -nogroup -nouser
Сервис пригодится, когда нужно найти что-то с параметрами, типа ограничения по датам изменения или доступа, размеру, правам доступа и т.д. Типичная история, когда надо проверить директорию веб сервера и снять с файлов все права на исполнение:# find /web/site/www -type f -name "*" -perm u+x -exec chmod 664 {} \; Программисты любят ставить 777 без разбора. Постоянно с этим сталкиваюсь. Когда у них что-то работает не так, они первым делом права доступа 777 ставят, а потом дальше разбираются.
#bash #terminal #find
👍64👎2
Давно не было заметок по полезным консольным командам под bash. В комментариях к заметке о find меня попросили поделиться своими шпаргалками для этой утилиты. Собрал наиболее универсальные и часто используемые конструкции.
Вывести только имена файлов. Поиск файлов пойдёт рекурсивно от той директории, где будет запущена команда:
Переместить найденные по маске файлы из одной директории в другую:
Найти все файлы по маске и сжать:
Переименовать все найденные файлы:
Подробный список файлов размером больше 100М с помощью ls:
Поиск файлов по содержимому (header.php):
Посчитать количество найденных файлов:
Найти файлы в определённом временном интервале:
Потом их можно сжать, переместить и т.д, как было показано в предыдущих примерах.
Искать без учёта регистра:
Поиск файлов, которые менялись сколько то дней назад и более:
или в течении последних 5 дней, но не позже:
или в определённом промежутке в минутах (10-20 минут назад):
Cортировка по дате изменения:
и обратная сортировка:
Захватил наиболее типовые ситуации, с которыми чаще всего приходится сталкиваться в консоли или скриптах автоматизации.
#bash #terminal #find
Вывести только имена файлов. Поиск файлов пойдёт рекурсивно от той директории, где будет запущена команда:
# find | awk -F '/' '{print $NF;}'Переместить найденные по маске файлы из одной директории в другую:
# find /mnt/backup/*site.ru* -type f -exec mv {} /web/sites/ \;Найти все файлы по маске и сжать:
# find /data/1c-bases-backup -type f -name 1Cv8.1CD -exec gzip '{}' \;Переименовать все найденные файлы:
# find /backup/sql -type f -name "*.sql.gz" -exec mv {} {}.old \;Подробный список файлов размером больше 100М с помощью ls:
# find /data -type f -size +100M -exec ls -lh '{}' \;Поиск файлов по содержимому (header.php):
# find /web/site.ru -type f -exec grep -i -H "header.php" {} \;Посчитать количество найденных файлов:
# find /home/user -type f | wc -lНайти файлы в определённом временном интервале:
# find /mnt/zz_archive -type f -newermt '2022-01-01 00:01' ! -newermt '2022-01-31 23:59'Потом их можно сжать, переместить и т.д, как было показано в предыдущих примерах.
Искать без учёта регистра:
# find /data -type f -iname FILE_NAMEПоиск файлов, которые менялись сколько то дней назад и более:
# find /data -type f -mtime +30или в течении последних 5 дней, но не позже:
# find /data -type f -mtime -5или в определённом промежутке в минутах (10-20 минут назад):
# find /data -type f -mmin -20 -mmin +10Cортировка по дате изменения:
# find /data -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -rи обратная сортировка:
# find /data -type f -printf '%TY-%Tm-%Td %TT %p\n' | sortЗахватил наиболее типовые ситуации, с которыми чаще всего приходится сталкиваться в консоли или скриптах автоматизации.
#bash #terminal #find
👍121👎1
Утилита find и время изменения файлов
Когда пишу скрипты с использованием find, регулярно натыкаюсь на одну и ту же неточность в своём понимании некоторых популярных параметров. Конкретно вот этих:
◽ mtime – время последнего изменения файла
◽ ctime – время создания файла
◽ atime – время последнего доступа к файлу
Когда вводишь команду:
ожидаешь найти все каталоги, созданные более суток назад, чтобы удалить их и освободить место на диске. Я специально взял именно сутки, так как тут сразу наглядно видно разночтение в ожидании и реальности. Find в таком виде покажет каталоги, созданные более трех суток назад.
Вот наглядный пример:
Директория 2022-06-05 старше суток, но в вывод find не попала. По факту параметр +1 означает всё, что старше двух суток. А для поиска старше суток, необходимо использовать +0.
Это связано с тем, что find определяет, как много 24-часовых периодов назад директория была создана. Любая дробная часть игнорируется, поэтому для соответствия -ctime +1 директория должна быть создана по крайней мере два дня назад.
Когда используешь большие интервалы, не обращаешь на такую мелочь внимания. А когда у тебя где-то на промежуточном хранилище не хватает свободного места и тебе надо точно рассчитать время хранения, такие нюансы становятся критичны.
Я с периодичностью раз в год-два разбираюсь с этим нюансом. Встречается редко, но когда наткнёшься, начинаешь вспоминать, как там find интерпретирует эти интервалы. Решил записать, может больше не буду забывать, но это вряд ли 🤷🏻♂️.
#bash #find #terminal
Когда пишу скрипты с использованием find, регулярно натыкаюсь на одну и ту же неточность в своём понимании некоторых популярных параметров. Конкретно вот этих:
◽ mtime – время последнего изменения файла
◽ ctime – время создания файла
◽ atime – время последнего доступа к файлу
Когда вводишь команду:
# find /mnt/backup -maxdepth 1 -type d -ctime +1ожидаешь найти все каталоги, созданные более суток назад, чтобы удалить их и освободить место на диске. Я специально взял именно сутки, так как тут сразу наглядно видно разночтение в ожидании и реальности. Find в таком виде покажет каталоги, созданные более трех суток назад.
Вот наглядный пример:
# date +"%Y-%m-%d %H-%M"2022-06-06 19-45# ls -lhdrwxr-xr-x 3 root root 4.0K Jun 2 17:09 2022-06-02drwxr-xr-x 3 root root 4.0K Jun 3 03:03 2022-06-03drwxr-xr-x 3 root root 4.0K Jun 4 03:03 2022-06-04drwxr-xr-x 3 root root 4.0K Jun 5 03:03 2022-06-05drwxr-xr-x 3 root root 4.0K Jun 6 03:03 2022-06-06# find /mnt/backup -maxdepth 1 -type d -ctime +1/mnt/backup/2022-06-04/mnt/backup/2022-06-03/mnt/backup/2022-06-02Директория 2022-06-05 старше суток, но в вывод find не попала. По факту параметр +1 означает всё, что старше двух суток. А для поиска старше суток, необходимо использовать +0.
Это связано с тем, что find определяет, как много 24-часовых периодов назад директория была создана. Любая дробная часть игнорируется, поэтому для соответствия -ctime +1 директория должна быть создана по крайней мере два дня назад.
Когда используешь большие интервалы, не обращаешь на такую мелочь внимания. А когда у тебя где-то на промежуточном хранилище не хватает свободного места и тебе надо точно рассчитать время хранения, такие нюансы становятся критичны.
Я с периодичностью раз в год-два разбираюсь с этим нюансом. Встречается редко, но когда наткнёшься, начинаешь вспоминать, как там find интерпретирует эти интервалы. Решил записать, может больше не буду забывать, но это вряд ли 🤷🏻♂️.
#bash #find #terminal
👍87👎2
Linux всегда меня восхищал и радовал простыми решениями по возможностям работы с текстовыми файлами через командную строку. Слово простые можно было бы взять в кавычки, так как в реальности не просто изучить синтаксис подходящих консольных утилит. Но никто не мешает найти готовое выражение и использовать его. В Windows чаще всего можно решить эти же задачи с помощью своих программ, но обычно это занимает больше времени.
Самый простой пример того, о чём я говорю — автоматическая замена определённого текста в заданных файлах. Мне лично чаще всего это нужно, когда что-то делаешь с исходниками сайтов. Помню, как свои первые сайты делал более 20-ти лет назад на чистом html в Dreamweaver. При этом страниц там было сотни. Обновлял вручную копипастом. Это было тяжело, но в то время большинство сайтов были статичными, так как бесплатных хостингов на php не существовало. Но это я отвлёкся, заметка планируется про другое.
Допустим, у вас есть какой-то большой сайт на php и вам надо во всех файлах заменить устаревшую функцию на новую. В общем случае замену текста можно сделать с помощью sed, примерно так:
Или посложнее пример с вырезанием вредоносного куска кода из всех файлов, которые заразил какой-то вирус. Допустим, это некий код следующего содержания:
Текста между тэгами script может быть много, поэтому искать проще всего по этому тэгу и началу строки с function aeaab19d(a).
Тут я использую ключ -r для поддержки регулярных выражений, конкретно
Можно ещё усложнить и выполнить замену кода между каких-то строк. Для усложнения возьмём какой-нибудь XML:
Заменим user01 на user02
Тут важны круглые скобки и \1 и \2. Мы в первой части выражения запомнили текст в круглых скобках, а во второй части его использовали — сначала первую скобку, потом вторую.
Это были примеры для одиночных файлов, а теперь добавляем сюда find и используем sed на любом наборе файлов, который найдёт find.
Добавляем к sed ключ -i для того, чтобы он сразу изменял файл. Кстати, для find наиболее популярные примеры можете посмотреть через тэг #find.
Очень аккуратно выполняйте массовые действия. Сначала всё отладьте на тестовых файлах. Потом сделайте бэкап исходных файлов. И только потом выполняйте массовые изменения. И будьте готовы быстро всё откатить обратно.
Примеры рекомендую записать. Если надо быстро что-то сделать, то сходу правильно регулярку вы так просто не наберёте. К тому же в таком использовании есть свои нюансы. К примеру, я так и не смог победить команду sed, которая удаляет весь код <script>, если внутри есть переход на новую строку. Вроде бы легко найти, как заставить
Не забывайте про сервисы, которые помогают отлаживать регулярки. Собрал их в отдельной заметке.
#linux #bash #script
Самый простой пример того, о чём я говорю — автоматическая замена определённого текста в заданных файлах. Мне лично чаще всего это нужно, когда что-то делаешь с исходниками сайтов. Помню, как свои первые сайты делал более 20-ти лет назад на чистом html в Dreamweaver. При этом страниц там было сотни. Обновлял вручную копипастом. Это было тяжело, но в то время большинство сайтов были статичными, так как бесплатных хостингов на php не существовало. Но это я отвлёкся, заметка планируется про другое.
Допустим, у вас есть какой-то большой сайт на php и вам надо во всех файлах заменить устаревшую функцию на новую. В общем случае замену текста можно сделать с помощью sed, примерно так:
# sed 's/old_function/new_function/g' oldfilename > newfilenameИли посложнее пример с вырезанием вредоносного куска кода из всех файлов, которые заразил какой-то вирус. Допустим, это некий код следующего содержания:
<script>function aeaab19d(a)...................</script>Текста между тэгами script может быть много, поэтому искать проще всего по этому тэгу и началу строки с function aeaab19d(a).
# sed -r 's/<script>function aeaab19d\(a\).*?<\/script>//' test.phpТут я использую ключ -r для поддержки регулярных выражений, конкретно
.*?. Можно ещё усложнить и выполнить замену кода между каких-то строк. Для усложнения возьмём какой-нибудь XML:
<username><![CDATA[user01]]></username><password><![CDATA[password01]]></password><dbname><![CDATA[database]]></dbname>Заменим user01 на user02
# sed -r 's/(<username>.+)user01(.+<\/username>)/\1user02\2/' test.xmlТут важны круглые скобки и \1 и \2. Мы в первой части выражения запомнили текст в круглых скобках, а во второй части его использовали — сначала первую скобку, потом вторую.
Это были примеры для одиночных файлов, а теперь добавляем сюда find и используем sed на любом наборе файлов, который найдёт find.
# find /var/www/ -type f -name \*.php -exec \sed -i -r 's/<script>function aeaab19d\(a\).*?<\/script>//' {} \;Добавляем к sed ключ -i для того, чтобы он сразу изменял файл. Кстати, для find наиболее популярные примеры можете посмотреть через тэг #find.
Очень аккуратно выполняйте массовые действия. Сначала всё отладьте на тестовых файлах. Потом сделайте бэкап исходных файлов. И только потом выполняйте массовые изменения. И будьте готовы быстро всё откатить обратно.
Примеры рекомендую записать. Если надо быстро что-то сделать, то сходу правильно регулярку вы так просто не наберёте. К тому же в таком использовании есть свои нюансы. К примеру, я так и не смог победить команду sed, которая удаляет весь код <script>, если внутри есть переход на новую строку. Вроде бы легко найти, как заставить
. в регулярках учитывать и переход на новую строку, но на практике у меня это не получилось сделать. Я не понял, как правильно составить выражение для sed. Не забывайте про сервисы, которые помогают отлаживать регулярки. Собрал их в отдельной заметке.
#linux #bash #script
👍94👎3
И вновь возвращаемся к рубрике с современными утилитами, которые можно использовать в качестве альтернативы более старым, потому что они уже поселились в официальных репозиториях. Речь пойдёт об уже упоминаемой мной несколько лет назад программе fd, которую можно использовать вместо find. Она приехала в стабильные репы:
Короткое название fd использовать не получится, потому что оно уже занято. Придётся использовать
В чём особенность fd? Авторы называют её более быстрой и дружелюбной к пользователю программой, по сравнению с find. В принципе, с этим не поспоришь. Ключи и синтаксис find нельзя назвать дружелюбным. Я по памяти могу только какие-то самые простые вещи делать. Всё остальное ищу в своих шпаргалках. Не понимаю, как подобные конструкции можно запоминать, если каждый день с ними не работаешь.
Ищем файл syslog в текущей директории:
Ищем файл в конкретной директории:
Ищем файл по всему серверу:
Вот то же самое, только с find:
По умолчанию find найдёт только полное совпадение по имени. Файл должен будет точно называться syslog, чтобы попасть в результаты поиска. Fd в примере отобразит все файлы, где встречается слово syslog. Это и интуитивнее, и проще для запоминания. Хотя этот момент субъективен. С find такой же поиск будет выглядеть вот так:
Отличия от find, которые отмечают авторы:
◽️Более скоростной поиск за счёт параллельных запросов. Приводят свои измерения, где это подтверждается.
◽️Подсветка результатов поиска.
◽️По умолчанию поиск ведётся без учёта регистра.
◽️Итоговые команды в среднем на 50% короче, чем то же самое получается с find.
⚠️ Отдельный ключ
Несколько простых примеров для наглядности. Поиск файлов с определённым расширением:
Найти все архивы и распаковать их:
Найти файлы с расширением gz и удалить одной командой rm:
Вызванный без аргументов в директории, fd рекурсивно выведет все файлы в ней:
Это примерно то же самое, что с find:
Только у fd вывод нагляднее, так как уже отсортирован по именам. А find всё вперемешку выводит. Ему надо sort добавлять, чтобы то же самое получилось:
Fd умеет результаты выводить не по одному значению на каждую строку, а непрерывной строкой с разделением с помощью так называемого NULL character. Все символы воспринимаются буквально, не являются специальными, их не надо экранировать. Актуально, когда результаты поиска имеют пробелы, кавычки, косые черты и т.д. Например, xargs умеет принимать на вход значения, разделённые NULL character. У него для этого отдельный ключ
Покажу на примере, как это работает:
Xargs не смог обработать файл с пробелом. А вот так смог:
И ничего экранировать не пришлось. Полезная возможность, стоит запомнить. Find то же самое делает через ключ
В заключении резюмирую, что fd не заменяет find, не претендует на это и не обеспечивает такую же функциональность, как у последнего. Он предоставляет обоснованные настройки по умолчанию для наиболее массовых применений поиска пользователями.
#terminal #linux #find
# apt install fd-findКороткое название fd использовать не получится, потому что оно уже занято. Придётся использовать
fdfind. Под Windows она, кстати, тоже есть:> winget install sharkdp.fdВ чём особенность fd? Авторы называют её более быстрой и дружелюбной к пользователю программой, по сравнению с find. В принципе, с этим не поспоришь. Ключи и синтаксис find нельзя назвать дружелюбным. Я по памяти могу только какие-то самые простые вещи делать. Всё остальное ищу в своих шпаргалках. Не понимаю, как подобные конструкции можно запоминать, если каждый день с ними не работаешь.
Ищем файл syslog в текущей директории:
# fdfind syslogИщем файл в конкретной директории:
# fdfind syslog /var/logИщем файл по всему серверу:
# fdfind syslog /Вот то же самое, только с find:
# find . -name syslog# find /var/log -name syslog# find / -name syslogПо умолчанию find найдёт только полное совпадение по имени. Файл должен будет точно называться syslog, чтобы попасть в результаты поиска. Fd в примере отобразит все файлы, где встречается слово syslog. Это и интуитивнее, и проще для запоминания. Хотя этот момент субъективен. С find такой же поиск будет выглядеть вот так:
# find / -name '*syslog*'Отличия от find, которые отмечают авторы:
◽️Более скоростной поиск за счёт параллельных запросов. Приводят свои измерения, где это подтверждается.
◽️Подсветка результатов поиска.
◽️По умолчанию поиск ведётся без учёта регистра.
◽️Итоговые команды в среднем на 50% короче, чем то же самое получается с find.
⚠️ Отдельный ключ
--exec-batch или -X в дополнение к традиционному --exec. Разница в том, что --exec выполняется параллельно для каждого результата поиска, а с помощью --exec-batch можно во внешнюю команду передать весь результат поиска. Это важный момент, который где-то может сильно выручить и упростить задачу. Даже если вам сейчас это не надо, запомните, что с fd так можно. Где-то в скриптах это может пригодиться.Несколько простых примеров для наглядности. Поиск файлов с определённым расширением:
# fdfind -e php -p /var/wwwНайти все архивы и распаковать их:
# fdfind -e zip -p /home/user -x unzipНайти файлы с расширением gz и удалить одной командой rm:
# fdfind -e gz -p /var/log -X rmВызванный без аргументов в директории, fd рекурсивно выведет все файлы в ней:
# cd /var/log# fdfindЭто примерно то же самое, что с find:
# find -name '*'Только у fd вывод нагляднее, так как уже отсортирован по именам. А find всё вперемешку выводит. Ему надо sort добавлять, чтобы то же самое получилось:
# find -name '*' | sortFd умеет результаты выводить не по одному значению на каждую строку, а непрерывной строкой с разделением с помощью так называемого NULL character. Все символы воспринимаются буквально, не являются специальными, их не надо экранировать. Актуально, когда результаты поиска имеют пробелы, кавычки, косые черты и т.д. Например, xargs умеет принимать на вход значения, разделённые NULL character. У него для этого отдельный ключ
-0, --null. Покажу на примере, как это работает:
# touch 'test test.log'# fdfind -e log...test test.log# fdfind -e log | xargs wc -l...wc: test: No such file or directorywc: test.log: No such file or directoryXargs не смог обработать файл с пробелом. А вот так смог:
# fdfind -0 -e log | xargs -0 wc -l...0 ./test test.logИ ничего экранировать не пришлось. Полезная возможность, стоит запомнить. Find то же самое делает через ключ
-print0:# find . -name '*.log' -print0 | xargs -0 wc -lВ заключении резюмирую, что fd не заменяет find, не претендует на это и не обеспечивает такую же функциональность, как у последнего. Он предоставляет обоснованные настройки по умолчанию для наиболее массовых применений поиска пользователями.
#terminal #linux #find
1👍102👎6