ServerAdmin.ru
31K subscribers
569 photos
46 videos
22 files
2.82K links
Авторская информация о системном администрировании.

Информация о рекламе: @srv_admin_reklama_bot
Автор: @zeroxzed

Второй канал: @srv_admin_live
Сайт: serveradmin.ru

Регистрация в РКН: https://vk.cc/cG1Urj
Download Telegram
В закладочках нашёл любопытный сервис, который очень полезен линуксоидам - конструктор для консольной команды FIND. Это такая типичная линуксовая утилита, у которой 100500 параметров и возможностей, ключи которой невозможно запомнить раз и навсегда. У меня огромная шпаргалка по 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
Давно не было заметок по полезным консольным командам под bash. В комментариях к заметке о 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 +10

Cортировка по дате изменения:
# 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
​​Утилита find и время изменения файлов

Когда пишу скрипты с использованием 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 -lh
drwxr-xr-x 3 root root 4.0K Jun 2 17:09 2022-06-02
drwxr-xr-x 3 root root 4.0K Jun 3 03:03 2022-06-03
drwxr-xr-x 3 root root 4.0K Jun 4 03:03 2022-06-04
drwxr-xr-x 3 root root 4.0K Jun 5 03:03 2022-06-05
drwxr-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
Linux всегда меня восхищал и радовал простыми решениями по возможностям работы с текстовыми файлами через командную строку. Слово простые можно было бы взять в кавычки, так как в реальности не просто изучить синтаксис подходящих консольных утилит. Но никто не мешает найти готовое выражение и использовать его. В Windows чаще всего можно решить эти же задачи с помощью своих программ, но обычно это занимает больше времени.

Самый простой пример того, о чём я говорю — автоматическая замена определённого текста в заданных файлах. Мне лично чаще всего это нужно, когда что-то делаешь с исходниками сайтов. Помню, как свои первые сайты делал более 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
И вновь возвращаемся к рубрике с современными утилитами, которые можно использовать в качестве альтернативы более старым, потому что они уже поселились в официальных репозиториях. Речь пойдёт об уже упоминаемой мной несколько лет назад программе fd, которую можно использовать вместо 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 '*' | sort

Fd умеет результаты выводить не по одному значению на каждую строку, а непрерывной строкой с разделением с помощью так называемого 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 directory
wc: test.log: No such file or directory

Xargs не смог обработать файл с пробелом. А вот так смог:

# 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