LinuxSkill - Сводки с прода и Шпаргалки
Следим за новостями Linux, DevOps и ИБ, чтобы быть готовым к любым факапам. Бонусом — плотные шпаргалки и чеклисты для ежедневной работы в терминале. 📩 По всем вопросам: @chorapov Зеркало в MAX: https://max.ru/LinuxSkill РКН https://vk.cc/cMUwm4
Ko'proq ko'rsatish📈 Telegram kanali LinuxSkill - Сводки с прода и Шпаргалки analitikasi
LinuxSkill - Сводки с прода и Шпаргалки (@linuxskill) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 10 747 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 11 103-o'rinni va Rossiya mintaqasida 59 284-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 10 747 obunachiga ega bo‘ldi.
30 Avgust, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -48 ga, so‘nggi 24 soatda esa 0 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 11.54% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 4.80% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 1 240 marta ko‘riladi; birinchi sutkada odatda 516 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 4 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent docker, linux, bash, devops, скрипт kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Следим за новостями Linux, DevOps и ИБ, чтобы быть готовым к любым факапам.
Бонусом — плотные шпаргалки и чеклисты для ежедневной работы в терминале.
📩 По всем вопросам: @chorapov
Зеркало в MAX: https://max.ru/LinuxSkill
РКН https://vk.cc/cMUwm4”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 31 Avgust, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
journalctl -p err -b
-b отсекает всё, что было до последней перезагрузки, -p err оставляет уровень Error и выше. Цифровой вариант -p 3 делает то же самое, но словом читается лучше.
Сузить окно до времени инцидента
journalctl --since "2026-08-13 23:00:00" \
--until "2026-08-14 01:00:00"
Нюанс: форматы вроде yesterday 23:00:00, которые кочуют по подборкам, systemd не разбирает — получишь Failed to parse timestamp. Проверил на systemd 255: отдельно yesterday работает, -2h работает, 23:00 работает, а вот их комбинация — нет. Надёжнее всегда писать полную дату.
Посмотреть, не прибило ли сервис ядро
dmesg -T --level=err,warn
dmesg -T | grep -i oom-killer
-T переводит секунды аптайма в нормальную дату. Фильтр по уровню полезнее грепа: покажет и OOM, и ошибки диска, и отвалившийся сетевой интерфейс.
Проверить блокировки SELinux
ausearch -m avc -ts recent
Нюанс: на Debian и Ubuntu команда чаще всего вернёт пустоту — там AppArmor, а не SELinux, и /sys/fs/selinux просто нет. Шаг актуален для RHEL-семейства; на Debian смотри journalctl -t audit и dmesg | grep -i apparmor.
Найти, кто сканирует сайт
awk -F'"' '{split($3,a," ");
if (a[1]==404) print $1}' access.log |
awk '{print $1}' | sort | uniq -c | sort -rn
Нюанс: ходовой вариант awk '$9 == 404' разваливается, если в URL попал пробел — поле уезжает, и строка молча не считается. У меня из трёх запросов с 404 такой вариант нашёл два. Разбор по кавычкам берёт код ответа там, где он реально лежит.
Для пары серверов этого хватает. Когда машин десятки, CLI перестаёт работать и нужен Loki или ELK — но и там первый вопрос будет тот же: какое окно и какой приоритет.
А с чего начинаете вы, когда прод упал и надо быстро локализовать причину?
#Linux #Logs #journalctl #Troubleshooting #DevOps
lsblk --discard
Нюанс: в подборках советуют hdparm -I /dev/sda | grep -i trim. На virtio-диске это не сработает вовсе — у меня вернуло Operation not permitted, потому что hdparm говорит по протоколу ATA, которого у виртуального диска нет. lsblk --discard показывает нужное для любого типа:
NAME DISC-GRAN DISC-MAX
vda 4K 1G
vdb 0B 0B
Ненулевые DISC-GRAN и DISC-MAX означают, что discard проходит. Нули — гипервизор его не отдаёт, дальше можно не настраивать.
Отдать блоки хосту прямо сейчас
fstrim -av --dry-run
fstrim -av
Сначала --dry-run: он делает всё то же самое, но без самого discard. У меня показал 0 B (dry run) trimmed on /dev/vda, а боевой запуск вернул 243.1 GiB trimmed.
Настроить регулярный TRIM
systemctl enable --now fstrim.timer
systemctl list-timers fstrim.timer
Нюанс: свой скрипт в /etc/cron.weekly писать не нужно — в пакете util-linux уже лежит готовый fstrim.timer с OnCalendar=weekly и разбросом запуска до 100 минут, чтобы виртуалки не пошли в discard одновременно.
Если всё-таки делаешь через cron, помни про две вещи. Скрипт без строки #!/bin/sh не выполнится: run-parts: failed to exec: Exec format error. И файл с точкой в имени, вроде fstrim.sh, run-parts молча пропустит.
Не включать онлайн-TRIM в fstab
UUID=xxxx / ext4 defaults,discard 0 1
Опция discard при монтировании шлёт запрос на очистку при удалении каждого файла. Пакетный TRIM раз в неделю делает то же самое, но одним заходом и в спокойное время.
Всё это работает, только если discard включён в настройках диска на самом гипервизоре. Иначе гость честно шлёт команды, а хост их игнорирует и продолжает копить мусор.
А вы fstrim по таймеру гоняете или руками, когда место кончилось?
#Linux #Virtualization #Proxmox #fstrim #DevOps
keepassxc-cli ls -R database.kdbx
Нюанс: без -R увидишь только верхний уровень. Вложенные записи в группах не покажет — легко решить, что база пустая.
Вытащить конкретный пароль в терминал
keepassxc-cli show -a Password database.kdbx "Production/DB"
Нюанс: обычный show без ключей выводит Password: PROTECTED вместо значения. Флаг -s раскрывает все поля, -a Password отдаёт только пароль одной строкой — удобно подставлять в скрипт.
Открыть базу с файлом ключей
keepassxc-cli ls -k keyfile.key database.kdbx
Тот же -k работает во всех подкомандах. Если пароля на базе нет вообще, добавь --no-password, иначе утилита будет ждать ввода.
Найти запись, когда не помнишь путь
keepassxc-cli search database.kdbx "DB"
Вернёт полный путь вида /Production/DB, который дальше подставляется в show.
Забрать всю базу разом
keepassxc-cli export -f csv database.kdbx
Отдаёт в stdout все записи вместе с паролями открытым текстом. Полезно при переезде, но перенаправлять это в файл на общей машине — плохая идея.
Про clip, который советуют для копирования пароля в буфер. Именно в сценарии «GUI лёг» он и не работает: без графической сессии команда отвечает All clipping programs failed. Tried xclip. Смысл в нём есть только в живой графике, где он же и чистит буфер через 10 секунд.
И про совет закрыть GUI перед работой в консоли. Проверил: при открытой базе KeePassXC создаёт рядом файл .kdbx.lock. Утилита о нём знает, так что «гарантированного повреждения» не будет — но менять базу из двух мест одновременно всё равно не стоит, последняя запись затрёт чужие правки.
А вы держите пароли в локальных kdbx или переехали на self-hosted Vaultwarden?
#Linux #KeePass #Security #CLI #DevOps
# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%C
ControlPersist 10m
Замерил на локальном sshd: первое подключение 0.22 секунды, второе и третье — по 0.01. Разница в двадцать раз, и это на loopback, где сети как таковой нет. На реальном канале с задержкой выигрыш будет больше.
Каталог ~/.ssh/sockets надо создать заранее, сам он не появится.
Не упереться в лимит длины пути
Нюанс: %C тут не для красоты. Классический %r@%h:%p на длинных именах хостов выходит за предел, и ssh отказывается работать:
ControlPath too long ('/root/.ssh/sockets/xxx...
-root@127.0.0.1:2222' >= 108 bytes)
Проверил на пути в 109 байт — ровно на границе. %C даёт хеш фиксированной длины и снимает вопрос совсем.
Проверить, жив ли мастер
ssh -O check user@host
Отвечает Master running (pid=924). Пригодится, когда непонятно, идёт ли новая сессия через кеш или поднимает соединение с нуля.
Сбросить залипшую сессию
ssh -O exit user@host
Печатает Exit request sent. и удаляет файл сокета. Нужно, когда на сервере поменялись ключи или конфиг, а мастер держит старую сессию.
Нюанс: если мастер-процесс умер не сам, а был убит, файл сокета остаётся сиротой. Прибил мастера через kill -9 — -O check стал отвечать Connection refused, но новое подключение прошло нормально: ssh увидел мёртвый сокет и поднял соединение заново.
Честный минус: ноутбук ушёл в сон с активным сокетом — при пробуждении получишь висящую сессию и таймаут вместо мгновенного входа. Лечится тем же -O exit, но сначала надо догадаться, что дело в нём.
А вы ControlPersist держите глобально на Host * или включаете точечно?
#Linux #SSH #Ansible #DevOps #TerminalUpgrade, поэтому фильтр видит легитимный веб-трафик. Проверял на версии 1.14.0, скачанной статическим бинарником с релизов.
Пробросить локальный TCP-порт в вебсокет
websocat --binary -E \
tcp-l:127.0.0.1:8080 ws://example.com/socket
Нюанс: без -E websocat печатает предупреждение про утечку сокетов при обслуживании нескольких клиентов. У меня оно вылезало на каждом запуске туннеля, с флагом лог чистый.
Держать сессию живой на нестабильной сети
websocat -t --ping-interval 10 \
- autoreconnect:ws://example.com/socket
Нюанс: autoreconnect: требует двух аргументов. Вариант с одним, который ходит по подборкам, падает: Specify ws:// or wss:// URI to connect to a websocket. Первым аргументом идёт источник данных — - для stdin или tcp-l: для туннеля.
Проверил разрыв: поднял клиент раньше сервера, в логе Reconnecting failed, процесс жив. Сервер появился — соединение поднялось само.
Отправить одно сообщение и выйти
echo "get_metrics" | websocat -1 ws://example.com/socket
Отправляет ровно один фрейм из stdin и закрывает сессию. Удобно дёргать из скрипта. Локальный эхо-сервер вернул get_metrics и завершился с кодом 0.
Пробить туннель на тестовый сервер с самоподписанным TLS
websocat -k wss://staging.example.com/socket
Флаг -k отключает проверку сертификата. Для стенда годится, дальше стенда — нет: MITM на таком туннеле не отличить от обычной работы.
Из полезного при отладке: websocat -t ws-l:127.0.0.1:1234 mirror: поднимает локальный эхо-сервер, на котором можно проверить свою команду, не выходя наружу.
Честный минус — синтаксис. Аргументы это цепочки специферов вида overlay:addrtype:address, и с непривычки половина попыток заканчивается Invalid command-line parameters. Плюс инкапсуляция в кадры съедает скорость, а на больших объёмах приходится крутить -B вручную.
А чем вы пробиваете туннель, когда наружу открыт только 443?
#Linux #websocat #Networking #Tunneling #DevOps
chattr +i /etc/passwd
Нюанс: useradd после этого выдаёт cannot open /etc/passwd и завершается с кодом 0. Пользователь не создаётся, скрипт не падает, мониторинг молчит. Снял атрибут — создался.
Разрешить логу только дозапись
chattr +a /var/log/secure
Нюанс: ротация делается переименованием, а его атрибут не пускает. Запустил logrotate на таком файле:
error: failed to rename: Operation not permitted
rc=0
Снова ноль на выходе. Файл не ротировался, cron считает, что всё прошло, логи растут до конца места.
Найти файлы с SUID и SGID
find / -xdev -perm /6000 -type f -ls 2>/dev/null
Нюанс: без -xdev поиск по корню вернул ноль файлов и код 1 — захлебнулся на /proc. С ним нашлось 16 штук. Пустой вывод легко принять за чистую систему. Старый синтаксис +6000 GNU find уже не понимает, отвечает invalid mode.
Выдать права одному пользователю
setfacl -m u:lisa:rw file
setfacl -b file
Единственное место без подвоха. После первой команды в ls -l появляется плюс: -rw-rw-r--+, после сброса исчезает — по нему и замечают ACL.
Поставить наблюдение за файлом
auditctl -w /etc/passwd -p wa -k pwd_change
Нюанс: правило живёт до перезапуска auditd. Постоянные пишутся в /etc/audit/rules.d/audit.rules.
Закрыть входящий трафик, оставшись в сессии
iptables -A INPUT -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
Порядок именно такой: политика последней. iptables -P INPUT DROP первой командой на удалённом сервере обрывает соединение сразу. И два уточнения: -m state до сих пор принимается, но актуален -m conntrack --ctstate, а iptables -V на 24.04 отвечает v1.8.10 (nf_tables) — правила уезжают в nftables.
У двух худших находок общее одно: команда не сработала, а код возврата ноль. Мониторингом такое не ловится.
А вы chattr +i на боевых конфигах ставите или считаете это ловушкой для самого себя?
#Linux #Security #Hardening #iptables #DevOps
ip -4 -br address show up
Нюанс: up фильтрует по состоянию линка, а не по наличию адреса. Погасил eth0 — с ключом он пропал из вывода совсем, без ключа виден как DOWN со всеми адресами на месте. Пустая строка тут не значит «адреса нет».
Второй адрес без алиасов вида eth0:1
ip address add 10.0.0.50/24 dev eth0
ip address del 10.0.0.50/24 dev eth0
Второй адрес встаёт рядом с первым, при удалении линк не дёргается.
Узнать, куда реально пойдёт пакет
ip route get 8.8.8.8
# 8.8.8.8 via 192.0.2.1 dev eth0 src 192.0.2.2
Не читает таблицу, а спрашивает у ядра готовое решение вместе с исходящим адресом. Для локального ответит local 192.0.2.2 dev lo.
Увидеть все таблицы маршрутизации
ip route show table all
Обычный show дал одну строку, table all — шесть, включая local с broadcast и host-маршрутами. С VPN и контейнерами разница уходит в десятки строк.
Посмотреть, кто есть в сети рядом
ip -4 neigh show
ip -6 neigh show
Нюанс: ip neigh — не ARP-таблица, как пишут в шпаргалках, а таблица соседей: ARP плюс IPv6 NDP. Без ключа -4 или -6 получишь обе вперемешку. arp -n показывал только первую, отсюда и путаница.
Сбросить кэш соседей
ip -s -s neigh flush dev eth0
Нюанс: без -s -s команда молчит и отдаёт код 0 — не отличишь «очистил десять записей» от «там было пусто». С ключом печатает удалённые записи и итог *** Round 1, deleting 1 entries ***.
Дать интерфейсу второе имя без даунтайма
ip link property add dev eth0 altname eno2
altname eno2 появляется в ip link show eth0, и по новому имени интерфейс находится: ip address show dev eno2 отдаёт eth0. Есть с ядра 5.8 и iproute2 5.8, на RHEL 7 синтаксис не разберётся.
Всё, что пишет, требует CAP_NET_ADMIN — в контейнере без --cap-add=NET_ADMIN упадёт.
А вы ip route get в отладке применяете или сразу лезете в show?
#Linux #iproute2 #Networking #DevOps #Debugset -euo pipefail сверху, set -x вокруг мутного места и ловушка DEBUG с read, чтобы останавливаться перед каждой командой. Прогнал этот набор на Ubuntu 24.04, bash 5.2. Три вещи из него ведут себя не так, как ожидаешь.
Сначала то, что работает без оговорок:
# падаем на ошибке, пустой переменной и в пайпах
set -euo pipefail
pipefail не декорация: false | true без него даёт код 0, с ним 1. А set -u ловит то, до чего не доберётся проверка синтаксиса:
echo "путь: /${UNSET_VAR}/data"
# bash: UNSET_VAR: unbound variable
Но `set -e` замолкает в условиях. Вызвал функцию через if — код возврата внутри перестал что-либо значить:
check() { false; echo "функция продолжила"; }
if check; then :; fi
# echo выполнился, rc=0
Трассировка. Обычно пишут просто set -x, но дефолтный PS4 печатает голый плюс — в скрипте на 300 строк не поймёшь, где ты:
PS4='+ ${BASH_SOURCE}:${LINENO}: '
set -x
do_something_risky
set +x
Теперь в каждой строке трассировки видно файл и номер:
+ g.sh:4: mkdir -p /tmp/zz
Пошаговый режим. Типовой рецепт — функция с read и ловушка DEBUG:
dbg() { read -p "$BASH_SOURCE:$LINENO? " _; }
trap 'dbg' DEBUG
В нём три поломки, и каждая тихая.
Первая: $LINENO и $BASH_SOURCE внутри функции указывают на саму функцию. На всех командах печаталось line=3 — строка, где стоит read. Реальные 6 и 7 не появились ни разу. Координаты надо передавать аргументами:
dbg() { read -r -p "[$1:$2] $3? " _; }
trap 'dbg "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"' DEBUG
Вторая: ловушка не заходит внутрь функций. Без set -T виден только вызов work, а команды в её теле пропадают — как раз там, где обычно и прячется баг.
set -T
Третья самая злая. read в ловушке читает тот же stdin, что и скрипт. Подал в цикл три строки — дошла одна:
printf 'alpha\nbeta\ngamma\n' | bash f.sh
получил: beta
Две строки съела отладка — отладчик изменил поведение отлаживаемого. Плюс при неинтерактивном stdin приглашение read -p не печатается вовсе, и скрипт молча проносится мимо пауз. Лечится перенаправлением:
dbg() { read -r -p "$1? " _ < /dev/tty; }
С ним прошли все три строки, паузы работали даже при stdin из /dev/null.
И про bash -n, который советуют как «проверку перед запуском». Он про синтаксис и только: незакрытый if поймал с кодом 2, а несуществующую команду и rm -rf /$UNSET_VAR/data пропустил с кодом 0.
Прогонял на двух машинах, bash 5.2.21 и 5.2.37 — поведение одинаковое.
А вы set -T вообще используете или обходитесь set -x?
#Linux #Bash #Debug #DevOps #Автоматизация# Ctrl-Z, потом
bg
jobs -l
disown %1
Вот тут первая шероховатость. В инструкциях пишут disown top, по имени команды. Оно работает, но ровно пока такой job один. Проверил: один sleep снимается нормально, два — ambiguous job spec и выход с кодом 1. Пиши %1 или PID, не имя.
Дальше открываем новую сессию в tmux и забираем процесс:
# PID берём из вывода jobs -l
reptyr 7972
Работает. Прогнал на top из одной tmux-сессии в другую: нулевой дескриптор сменился с /dev/pts/0 на /dev/pts/2, вывод продолжился в новом окне.
При этом reptyr напечатал [-] Timed out waiting for child stop. — и всё равно перенёс. Причём это вылезло на обеих машинах и на разных версиях, так что предупреждение можно игнорировать.
А вот чего в инструкциях обычно нет. По умолчанию в Debian и Ubuntu kernel.yama.ptrace_scope равен 1: подцепиться можно только к своему потомку. Процесс из старой ssh-сессии новой оболочке не потомок.
Запустил от обычного пользователя — получил отказ:
Unable to attach to pid 2162:
Operation not permitted
Дальше reptyr сам подсказывает посмотреть ptrace_scope — за это спасибо автору. Лечится так:
cat /proc/sys/kernel/yama/ptrace_scope
# 0 — классические правила ptrace
sysctl -w kernel.yama.ptrace_scope=0
С нулём тот же скрипт перенёс процесс на /dev/pts/5. Но это ослабление защиты: любой процесс под тем же uid сможет подцепиться к любому другому. Держать так постоянно на боевой машине я бы не стал. Под root, кстати, всё работает и при единице — CAP_SYS_PTRACE обходит yama.
Есть флаг -T: крадёт весь терминальный сеанс и по описанию должен выручать, когда у процесса есть дети. Взял конвейер sleep 400 | cat, натравил reptyr -T — и ничего. Ни ошибки, ни переноса: лог пустой, tty прежний. В чём подвох, не разобрался.
И про версии. На одной машине приехал reptyr 0.9.0-1, на другой при той же Ubuntu 24.04 — 0.8.0. Флаги в обеих одинаковые, но длинных опций нет ни там, ни там: reptyr --help отвечает invalid option.
А вы reptyr вообще применяли в бою или проще перезапустить и не рисковать?
#Linux #Bash #tmux #reptyr #DevOps
R=zabbix/zabbix
curl -s "https://api.github.com/repos/$R" \
| jq '{pushed_at, archived, license: .license.spdx_id}'
Три поля решают почти всё. archived: true — проект заморожен официально, дальше можно не смотреть.
2. Сколько на самом деле прошло с последнего пуша
P=$(curl -s "https://api.github.com/repos/$R" \
| jq -r .pushed_at)
echo $(( ($(date +%s) - $(date -d "$P" +%s)) / 86400 ))
Глазами дату читать бесполезно — «2024-03-11» не выглядит страшно, пока не увидишь рядом число 881.
3. Bus factor
S=$(date -u -d '90 days ago' +%Y-%m-%d)
curl -s "https://api.github.com/repos/$R/commits\
?since=$S&per_page=100" \
| jq -r '[.[] | (.author.login // "?")]
| group_by(.) | map("\(length) \(.[0])") | .[]' \
| sort -rn | head -5
Если весь список — один ник, проект держится на одном человеке. Это не приговор, но знать надо заранее, а не когда он выгорит.
Тут спрятаны грабли, на которые я сам наступил. Без скобок вокруг .author.login // "?" конвейер молча теряет коммиты, у которых автор не привязан к аккаунту GitHub. На макете из пяти коммитов jq вернул четыре. Оператор `//` в jq применяется ко всему потоку, а не к каждому элементу — скобки обязательны.
4. Лицензия
В первом же запросе смотри на spdx_id. Значение NOASSERTION означает, что GitHub не смог сопоставить файл лицензии ни с одной стандартной. Чаще всего это BSL, SSPL или самописный текст с ограничениями на коммерческое использование. Открывай LICENSE руками.
5. Есть ли пакет в репах твоего дистрибутива
for p in netdata zabbix-server-pgsql; do
v=$(apt-cache madison "$p" 2>/dev/null | head -1)
printf '%-22s %s\n' "$p" "${v:-НЕТ В РЕПАХ}"
done
Проверял на Ubuntu 24.04: netdata нашёлся в noble/universe, zabbix-server-pgsql — нет, ставить придётся из репозитория вендора. Отдельная засада: apt-cache madison и apt-cache policy возвращают код 0, даже когда пакета не существует, просто печатают пустоту. Конструкция apt-cache policy X || echo "нет" не сработает никогда — проверяй пустоту переменной, как выше.
6. Помни про лимит
Анонимно GitHub API даёт 60 запросов в час на IP, и на общем адресе они кончаются мгновенно — я на этом словил 403 посреди проверки. С персональным токеном лимит 5000:
curl -s -H "Authorization: Bearer $GH_TOKEN" \
https://api.github.com/rate_limit | jq .rate
Честный минус метода: API показывает активность, а не качество. Проект может коммитить каждый день и при этом быть непригодным, а может годами лежать без изменений, потому что он просто дописан. Так что это фильтр первого уровня, а не вердикт.
#Linux #DevOps #GitHub #jq #Чеклист
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' file.log
На моём тестовом логе выдал 5.15.0.91 (версия ядра), 999.999.999.999 и 1.2.3.4 — откушенный кусок от 1.2.3.4.5. Октеты не проверяются, границы тоже. -w не спасает: точка не словесный символ.
grep -oP '(?<![\d.])((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\
\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?![\d.])' file.log
Мусор ушёл. Цена — -P, а это PCRE, на BSD-grep не заработает.
Пустые строки удаляются не все
sed -i '/^$/d' file.txt
^$ — это строка нулевой длины. Строка из трёх пробелов останется, строка с табом останется. Проверил через cat -A. Правильно так:
# сначала посмотреть, что уйдёт
sed -n '/^[[:space:]]*$/p' file.txt
# и только потом править, с бэкапом
sed -i.bak -E '/^[[:space:]]*$/d' file.txt
-i без .bak переписывает файл на месте. Один раз ошибёшься с шаблоном — восстанавливать неоткуда.
URL глотает всё до пробела
grep -Eo 'https?://[^ ]+' file.txt
На строке см. (http://foo.org/x) и "https://bar.io/y" вернул адреса вместе со скобкой и кавычкой. А в строке с табуляцией утащил ещё и следующее слово — таб это не пробел.
grep -Eo 'https?://[^[:space:]<>"()]+[^[:space:]<>"(),.;:]' \
file.txt
.{100,} — это сто и больше
Комментарий обещает «длиннее 100 символов», регулярка ловит и ровно стошную. Плюс зависит от локали: строка из 60 кириллических букв под LC_ALL=C считается длинной (120 байт), под UTF-8 — нет. Проверил обе, результат разный. Если нужны символы и строго больше — берите awk 'length($0) > 100'.
По мелочи: ^# не видит комментарии с отступом, -v 'ERROR' выкидывает строки со словом NOERROR, а \s в седьмом пункте — GNU-расширение, на macOS и busybox отвалится, там нужен [[:space:]].
Регулярки для email и извлечения доменов, кстати, оказались нормальными. Придираться не к чему.
Забирайте исправленный набор в закладки — пригодится, когда в три часа ночи будете грепать чужой лог.
#Linux #Bash #grep #sed #regex #DevOps
# фильтр из конспекта
strace -f -e trace=open,openat ./finder.sh \
| grep myapp
# пусто
# весь файловый класс
strace -f -e trace=%file ./finder.sh | grep myapp
# newfstatat(AT_FDCWD, "/etc/myapp/config.ini",
# 0x7ffc0f32bee0, 0) = -1 ENOENT
Программе незачем открывать файл, чтобы понять, что его нет. Она зовёт newfstatat, и фильтр по open его срезает. Фильтр отрезает ровно то, ради чего ты запускал strace.
Заодно: open( в выводе cat — 0 вхождений, openat( — 3. glibc на x86_64 давно ходит через openat. Искать в трейсе open() бессмысленно.
Рабочий вариант
# -Z печатает только вызовы, вернувшие ошибку
strace -f -Z -e trace=%file \
-o /tmp/t.log ./myapp
grep -E 'ENOENT|EACCES' /tmp/t.log
-o тут не для красоты. Без него 2>&1 | grep смешает трейс с выводом самого приложения, у меня в грепнутый поток прилетело cat: /nonexistent: No such file от подопытного.
Если процесс уже крутится
PID=$(systemctl show -p MainPID --value nginx)
sudo strace -f -Z -e trace=%file -p $PID
Честно: эту связку я проверял только по документации, systemd-хоста под рукой не было. Синтаксис --value живёт с systemd 230.
Что читать в ошибках
▪️ ENOENT — такого пути нет
▪️ EACCES — нет прав на файл или каталог
▪️ ENOTDIR — в середине пути не каталог
▪️ ELOOP — symlink закольцевался
Половина «config not found» в проде — это EACCES, а не отсутствие файла.
Грабли: -Z появился в strace 5.2 от 12 июля 2019. На старом RHEL 7 со strace 4.12 его нет, там остаётся grep по ENOENT. В контейнере нужен --cap-add=SYS_PTRACE. И трейс тормозит процесс в разы — на живом сервисе цепляйся коротко.
А вы чем ловите такие вещи — strace, ltrace или сразу lsof -p?
#Linux #strace #DevOps #Debug #SRE-e trace=open,openat, увидишь, где программа ищет конфиг. Решил проверить перед постом. Ubuntu 24.04, strace 6.8. Не увидел ничего.
Подопытный — скрипт, который проверяет конфиг через test -f:
# фильтр из конспекта
strace -f -e trace=open,openat ./finder.sh \
| grep myapp
# пусто
# весь файловый класс
strace -f -e trace=%file ./finder.sh | grep myapp
# newfstatat(AT_FDCWD, "/etc/myapp/config.ini",
# 0x7ffc0f32bee0, 0) = -1 ENOENT
Программе незачем открывать файл, чтобы понять, что его нет. Она зовёт newfstatat, и фильтр по open его срезает. Фильтр отрезает ровно то, ради чего ты запускал strace.
Заодно: open( в выводе cat — 0 вхождений, openat( — 3. glibc на x86_64 давно ходит через openat. Искать в трейсе open() бессмысленно.
Рабочий вариант
# -Z печатает только вызовы, вернувшие ошибку
strace -f -Z -e trace=%file \
-o /tmp/t.log ./myapp
grep -E 'ENOENT|EACCES' /tmp/t.log
-o тут не для красоты. Без него 2>&1 | grep смешает трейс с выводом самого приложения, у меня в грепнутый поток прилетело cat: /nonexistent: No such file от подопытного.
Если процесс уже крутится
PID=$(systemctl show -p MainPID --value nginx)
sudo strace -f -Z -e trace=%file -p $PID
Честно: эту связку я проверял только по документации, systemd-хоста под рукой не было. Синтаксис --value живёт с systemd 230.
Что читать в ошибках
▪️ ENOENT — такого пути нет
▪️ EACCES — нет прав на файл или каталог
▪️ ENOTDIR — в середине пути не каталог
▪️ ELOOP — symlink закольцевался
Половина «config not found» в проде — это EACCES, а не отсутствие файла.
Грабли: -Z появился в strace 5.2 от 12 июля 2019. На старом RHEL 7 со strace 4.12 его нет, там остаётся grep по ENOENT. В контейнере нужен --cap-add=SYS_PTRACE. И трейс тормозит процесс в разы — на живом сервисе цепляйся коротко.
А вы чем ловите такие вещи — strace, ltrace или сразу lsof -p?
#Linux #strace #DevOps #Debug #SREkill -9. Но перезапуск вслепую не решает проблему — он уничтожает контекст, и сбой повторится. Показываю, как заглянуть внутрь зависшего приложения на лету и поставить точный диагноз, не останавливая процесс.
Базовая диагностика зависания
# 1. Находим PID проблемного процесса по имени.
pidof my_process
# 2. Подключаемся к процессу на лету и слушаем ввод-вывод.
# -t добавит таймстампы: видно, КОГДА процесс замер.
sudo strace -tt -p <PID> -e trace=read,write
Расширенный мониторинг дескрипторов
# 3. Отслеживаем ВСЕ файловые операции.
# ВАЖНО: не 'open', а группа %file — современный glibc зовёт openat(), а не open(),
# поэтому одиночный 'open' почти ничего не покажет. %file ловит open, openat, stat, access.
sudo strace -p <PID> -e trace=read,write,%file
# Если ждёшь именно сетевую блокировку (отвалившаяся БД, зависший сокет):
sudo strace -p <PID> -e trace=%net
Анализ блокировки (Read Blocking)
# 4. Если вывод strace замирает на строке вида:
# read(5,
# — процесс жив, но ждёт данных в дескриптор №5.
# Отключаемся (Ctrl+C НЕ убьёт процесс) и смотрим, что это за дескриптор:
sudo lsof -p <PID> -a -d 5
# Быстрая альтернатива без lsof — прямо из /proc:
sudo ls -l /proc/<PID>/fd/5
Такой подход превращает абстрактное «оно зависло» в понятную картину: процесс может просто ждать read() из сокета из-за отвалившейся БД или недоступного пайпа, а не находиться в deadlock. Диагноз без правки кода и простоя на рестарт.
❗️❗️❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Strace #Troubleshooting #DevOps #SysAdmin