DimaSOS

Терминал

Linux-команды, которые нужны при разборе продакшена и настройке серверов.

#Процессы

ps aux | grep -i nginx
ps -eo pid,ppid,rss,pcpu,comm --sort=-rss | head -15
pgrep -a java
pidof nginx

--sort=-rss сразу показывает, кто ест память. rss в килобайтах.

top -o %MEM
htop
btop

Интерактивно. В top: M — сортировка по памяти, P — по CPU, 1 — раскладка по ядрам.

kill 12345          # SIGTERM, вежливо
kill -9 12345       # SIGKILL, без шансов на очистку
pkill -f "python.*worker"
killall -u www-data

pkill -f матчит по всей командной строке — осторожно, шаблон может попасть в собственную оболочку.

Практический случай: pkill -f script.sh, запущенный из bash -c, убивает и сам вызывающий процесс, потому что шаблон есть в его cmdline.

lsof -p 12345 | head -20
lsof -i :8443
lsof +D /var/log | head
ls -l /proc/12345/fd | wc -l

Что держит процесс: файлы, сокеты, порты. Последняя команда — счётчик открытых дескрипторов, растёт при утечке.

nohup ./long-task.sh > out.log 2>&1 &
disown
jobs
fg %1

Отвязать задачу от сессии. Для чего-то серьёзного лучше systemd-юнит или tmux.

strace -p 12345 -f -e trace=network 2>&1 | head -40
strace -c -p 12345

Что процесс делает с системой. -c — сводка по syscall'ам, быстро показывает, где процесс завис.

#Файлы, поиск, права

find /var/log -type f -size +50M -exec ls -lh {} \;
find . -name "*.kt" -newermt "-3 days"
find . -type d -name build -prune -o -name "*.log" -print
find /tmp -type f -mtime +7 -delete

-prune исключает каталоги из обхода — без него find лезет в build и node_modules.

grep -rn "TODO" --include="*.kt" src/
grep -rl "apiKey" . | head
grep -c ERROR app.log
grep -A3 -B3 "Exception" app.log | head -40
grep -Ev "^\s*(#|$)" nginx.conf

-l только имена файлов, -c счётчик, -A/-B контекст. Последняя команда убирает комментарии и пустые строки из конфига.

du -xh --max-depth=2 / 2>/dev/null | sort -rh | head -15
du -sh /var/log/*
df -h
df -i          # иноды, если «нет места», а место есть

-x не уходит на другие ФС. Кончившиеся иноды выглядят как No space left при свободных гигабайтах.

chmod 640 secret.key
chmod +x script.sh
chown www-data:adm /var/log/app.log
umask 027

Числа: владелец/группа/остальные, 4=r, 2=w, 1=x. 640 — владельцу чтение-запись, группе чтение, остальным ничего.

tar czf backup.tar.gz -C /etc nginx
tar xzf backup.tar.gz -C /tmp/restore
tar tzf backup.tar.gz | head
zcat app.log.1.gz | grep ERROR

-C меняет каталог до упаковки — так в архиве не будет лишних уровней путей. zcat/zgrep читают .gz без распаковки.

ln -s /var/www/site /srv/current
readlink -f /srv/current
stat app.log

Симлинки и метаданные файла.

#Обработка текста

awk '{print $1, $9}' access.log | head
awk '$9 >= 500 {print}' access.log | wc -l
awk -F: '{print $1}' /etc/passwd | head

$1, $9 — поля, -F задаёт разделитель. Для логов часто короче, чем cut+grep.

sed -n '100,120p' app.log
sed 's/old/new/g' file.txt          # в stdout
sed -i.bak 's/old/new/g' file.txt   # на месте, с бэкапом
sed '/^#/d' config.ini

-i.bak — правка на месте с копией. Без суффикса откатиться будет нечем.

sort access.log | uniq -c | sort -rn | head -20
cut -d' ' -f1 access.log | sort -u | wc -l
tr -s ' ' | tr '[:upper:]' '[:lower:]'

Классика подсчёта частот: sort | uniq -c | sort -rn. uniq требует отсортированного входа.

tail -f app.log
tail -f app.log | grep --line-buffered ERROR
tail -n 200 app.log
head -c 2000 app.log
watch -n 2 'ss -tn | wc -l'

--line-buffered обязателен, иначе grep буферизует и вывод появляется рывками по 4 КБ.

wc -l app.log
diff -u old.conf new.conf
comm -13 <(sort a.txt) <(sort b.txt)

comm -13 — строки, которые есть только во втором файле.

#systemd

systemctl status nginx
systemctl start|stop|restart|reload nginx
systemctl enable --now myapp
systemctl disable --now myapp
systemctl is-active nginx

reload перечитывает конфиг без разрыва соединений, restart роняет процесс. Для nginx почти всегда нужен reload.

systemctl list-units --type=service --state=running
systemctl list-unit-files --state=enabled
systemctl cat nginx
systemctl show nginx -p MainPID,MemoryCurrent

cat показывает юнит вместе со всеми override'ами — удобнее, чем искать файлы руками.

systemctl edit myapp            # override-фрагмент
systemctl daemon-reload         # после правки юнитов
systemctl reset-failed myapp

edit создаёт /etc/systemd/system/myapp.service.d/override.conf — правильный способ менять пакетные юниты.

[Unit]
Description=My worker
After=network-online.target

[Service]
Type=simple
User=app
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/worker
Restart=on-failure
RestartSec=5
MemoryMax=512M

[Install]
WantedBy=multi-user.target

Минимальный рабочий юнит. MemoryMax спасает хост от процесса, который течёт.

systemd-analyze blame | head -10
systemd-analyze critical-chain

Что тормозит загрузку.

#journalctl и логи

journalctl -u nginx -n 100 --no-pager
journalctl -u nginx -f
journalctl -u nginx --since "1 hour ago"
journalctl --since "2026-08-25 10:00" --until "2026-08-25 11:00"

--no-pager нужен в скриптах, иначе команда зависнет в ожидании пейджера.

journalctl -p err -b
journalctl -k                      # ядро
journalctl -b -1                   # предыдущая загрузка
journalctl --list-boots

-p err и хуже. -b -1 — первое, что смотреть после неожиданной перезагрузки.

journalctl --disk-usage
journalctl --vacuum-size=200M
journalctl --vacuum-time=14d

Журнал по умолчанию растёт до 10% раздела. Постоянный лимит — SystemMaxUse в /etc/systemd/journald.conf.

logrotate -d /etc/logrotate.d/nginx    # dry-run
logrotate -f /etc/logrotate.d/nginx    # принудительно
cat /var/lib/logrotate/status

-d ничего не делает, только печатает решение — так проверяется правило перед применением.

/var/log/nginx/*.log {
    daily
    maxsize 50M
    rotate 7
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    postrotate
        invoke-rc.d nginx rotate >/dev/null 2>&1
    endscript
}

daily без maxsize — типовая ошибка: при всплеске трафика файл раздувается за часы, а ротация ждёт суток.

#Разное полезное

free -h
uptime
vmstat 1 5
iostat -x 1 3
sar -u 1 5

load average сравнивают с числом ядер (nproc): 4.0 на 4 ядрах — полная загрузка, не перегрузка.

dpkg -l | grep -i openssl
apt list --installed | wc -l
apt-get -s autoremove
apt-get clean
dpkg -S /usr/bin/curl          # какой пакет владеет файлом

-s у apt — симуляция, показывает план без выполнения.

tmux new -s work
tmux attach -t work
tmux ls
# Ctrl-b d — отсоединиться, Ctrl-b c — новое окно, Ctrl-b % — сплит

Обязательно для долгих задач по ssh: обрыв связи не убьёт процесс.

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@host
ssh -i ~/.ssh/key -p 2222 user@host
scp file.txt host:/tmp/
rsync -avz --progress ./dist/ host:/var/www/site/

rsync с завершающим слэшем в источнике копирует содержимое, без слэша — сам каталог. Классический источник сюрпризов.

Host myserver
    HostName 203.0.113.10
    User root
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Запись в ~/.ssh/config. Дальше просто ssh myserver.

СимптомЧто смотреть
No space left, а место естьdf -i — кончились иноды
Диск полон, но du не показываетудалённый файл держит процесс: lsof +L1
Сервис не поднимается после правки юнитаsystemctl daemon-reload
Address already in usess -tlnp | grep :ПОРТ
Скрипт зависает в CIjournalctl без --no-pager
Логи растут скачкамиlogrotate без maxsize
grep в пайпе выводит рывкаминужен --line-buffered