Справочник ключевых терминов курса Linux & Bash для Junior Data Engineer.
Центральный компонент ОС, работающий в привилегированном режиме CPU (ring 0 на x86). Управляет физическими ресурсами: процессорным временем (scheduler), оперативной памятью (virtual memory, paging), вводом-выводом, файловыми системами (через VFS), сетевым стеком и устройствами (через драйверы). Прикладные программы работают в user space (ring 3) и общаются с ядром через системные вызовы (syscalls): open(), read(), write(), fork(), execve(), mmap(). На Ubuntu 26.04 LTS — Linux kernel 6.11+. Проверить версию: `uname -r`. Kernel и дистрибутив — разные вещи: Linux — это только kernel, а Ubuntu/Debian — kernel + GNU userland + пакеты.
uname -r # 6.11.0-15-generic
uname -a # вся информация
cat /proc/version # кем и когда собрано
strace -c ls # какие syscalls делает lsПолная сборка ОС: Linux kernel + GNU coreutils + libc (glibc или musl) + init-система (обычно systemd) + пакетный менеджер + набор предустановленного софта. Дистрибутивы делятся по семействам: Debian-based (Debian, Ubuntu, Mint — apt/dpkg), Red Hat-based (RHEL, Fedora, Rocky, Alma — dnf/rpm), Arch-based (pacman), Alpine (apk, musl libc). Различия: версия ядра (LTS vs rolling), стабильность пакетов, политика релизов (Ubuntu LTS — раз в 2 года, Debian — ~раз в 2 года, Arch — rolling). Для серверов DE чаще всего: Ubuntu LTS или Debian stable.
cat /etc/os-release
# NAME="Ubuntu"
# VERSION="26.04 LTS (Resolute Raccoon)"
lsb_release -a
hostnamectl # systemd-вариантПрограмма-интерпретатор командной строки, читающая ввод пользователя и запускающая программы. НЕ часть ядра — обычный user-space process. Основные shells: sh (POSIX baseline), bash (Bourne Again Shell, GNU, стандарт для Linux), zsh (расширенный, default на macOS с 2019), fish (user-friendly), dash (быстрый POSIX, default `/bin/sh` в Debian/Ubuntu для скриптов). Shell делает: parsing команды, expansion (glob, переменные, command substitution), запуск через fork+execve, redirect IO, pipes между процессами, job control. Login shell читает `.profile` / `.bash_profile`, interactive non-login — `.bashrc`. На Ubuntu 26.04 default — bash 5.3.
echo $SHELL # /bin/bash
cat /etc/shells # доступные shells
chsh -s /usr/bin/zsh # сменить login shell
bash --version # GNU bash 5.3.xИзначально — физическое устройство (телетайп, VT100), сейчас — эмулятор терминала (xterm, GNOME Terminal, iTerm2, Alacritty, Kitty), программа, рисующая текст и читающая клавиатуру. Между терминалом и shell стоит TTY-драйвер ядра (`/dev/pts/N` для pseudo-terminal). Терминал НЕ равен shell: bash может работать без терминала (cron, script), терминал может запускать любой shell. Управляющие последовательности (ANSI escape codes) рисуют цвета, перемещают курсор. SSH-сессия — это удалённый TTY через сеть. Проверить: `tty` показывает device file текущего терминала.
tty # /dev/pts/3
ps -o tty,pid,cmd # связь процессов с TTY
echo -e '\033[31mRED\033[0m' # ANSI escape
stty -a # настройки TTY-драйвераТекст, который shell выводит перед командой пользователя. В bash определяется переменной PS1 (primary prompt) и поддерживает escape-последовательности: `\u` — username, `\h` — hostname, `\w` — current directory, `\$` — # для root и $ для обычного пользователя, `\[\033[...]\]` — non-printing цветовые escape. PS2 — continuation prompt (после открытой скобки или незакрытой кавычки). DE часто кастомизирует PS1 для показа Git-ветки, k8s-контекста, AWS-профиля. На production-серверах PS1 обычно подсвечивает hostname красным (PROD), чтобы случайно не выполнить `rm -rf` на боевом сервере.
echo $PS1
# \u@\h:\w\$
# Custom prompt с git branch и цветом
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '
# В .bashrc для постоянстваСтандарт раскладки директорий в Linux (LSB / Linux Foundation). Определяет, что и где должно лежать: `/bin`, `/sbin`, `/usr/bin`, `/usr/sbin` — исполняемые файлы; `/etc` — конфиги системы (только text); `/var` — изменяемые данные (logs в `/var/log`, БД в `/var/lib`, кэш в `/var/cache`); `/home/<user>` — пользовательские каталоги; `/tmp` — временные файлы (часто tmpfs в RAM, чистится при reboot); `/usr` — read-only user-installed программы; `/opt` — сторонние пакеты; `/proc` — virtual FS с процессами; `/sys` — virtual FS с устройствами; `/dev` — device files. В современных дистрибутивах `/bin` и `/sbin` — symlinks на `/usr/bin` и `/usr/sbin` (merged-/usr).
ls / # корневые директории
ls /var/log # логи системы и сервисов
cat /etc/os-release # конфиг с инфой ОС
df -h /tmp # часто отдельный mount (tmpfs)Структура данных в файловой системе, хранящая метаданные одного файла: размер (size), права (mode/permissions), владельца (UID), группу (GID), timestamps (atime, mtime, ctime), количество hard links, и указатели на блоки данных (direct, indirect, double-indirect — в ext4). Имя файла НЕ хранится в inode — оно хранится в directory entry и ссылается на inode по номеру. Поэтому hard link — это вторая directory entry, указывающая на ТОТ ЖЕ inode (расшаренный). При создании файла файловая система выделяет inode из inode-таблицы; их количество фиксировано при `mkfs`. Когда inode заканчиваются — `df` показывает место свободно, но `touch` падает с 'No space left on device'.
ls -i file.txt # 12345678 file.txt
stat file.txt # все метаданные inode
# Size, Blocks, IO Block, Inode, Links, Access, Uid, Gid
df -i # сколько inodes свободноНеотрицательное целое число, которое ядро возвращает процессу при `open()` и используется для последующих read/write/close. Каждый процесс имеет свою таблицу FD (хранится в kernel space). По умолчанию открыты три FD: 0 — stdin, 1 — stdout, 2 — stderr. FD указывает на запись в системной таблице open files, которая ссылается на inode. Лимит FD на процесс — `ulimit -n` (часто 1024, для серверов 65535+). При превышении — 'Too many open files'. Pipes, sockets, devices тоже представлены через FD. В `/proc/<pid>/fd/` лежат симлинки на открытые файлы процесса.
ls -la /proc/$$/fd # FD текущего shell
# 0 -> /dev/pts/3 stdin
# 1 -> /dev/pts/3 stdout
# 2 -> /dev/pts/3 stderr
ulimit -n # лимит FD
exec 3>log.txt # открыть FD 3 на запись
echo hello >&3Запущенный экземпляр программы со своим адресным пространством, FD-таблицей, переменными окружения, working directory, UID/GID. Идентифицируется PID (process ID). Создаётся через `fork()` (клонирует parent) или `clone()` + `execve()` (запускает новую программу). Каждый процесс имеет parent (PPID); init/systemd (PID 1) — корень дерева. Состояния: R (running), S (sleeping interruptible), D (uninterruptible — обычно IO), Z (zombie — завершился, parent не вызвал wait()), T (stopped). Threads — это процессы, делящие address space (clone с CLONE_VM). Информация о процессах — в `/proc/<pid>/`.
ps aux # все процессы
ps -ef --forest # дерево процессов
pstree -p # граф
cat /proc/$$/status # детали shell-процесса
top # интерактивноДолгоживущий фоновый процесс без управляющего терминала, обычно запускается при старте системы и работает до shutdown. По соглашению имя оканчивается на `d`: sshd, cron(d), systemd, postgres(d), nginx (без d). Классический daemonize: fork -> setsid (новая сессия) -> fork снова -> chdir / -> close stdin/stdout/stderr -> выполнять работу. В systemd-эре daemon чаще пишут как обычные foreground-процессы, а systemd сам управляет жизненным циклом через unit-файл. Logs daemonа уходят либо в `/var/log/`, либо в journald (`journalctl -u <unit>`).
systemctl list-units --type=service
systemctl status sshd
ps -ef | grep -E '(sshd|cron|systemd)' | head
journalctl -u sshd -n 50Асинхронное уведомление процессу от ядра или другого процесса. Каждый сигнал имеет имя и номер. Самые важные: SIGTERM (15) — мягкое завершение, default для `kill <pid>`, процесс может обработать (cleanup); SIGKILL (9) — принудительное завершение, нельзя перехватить или игнорировать, ядро убивает немедленно; SIGINT (2) — Ctrl+C; SIGHUP (1) — terminal disconnect, часто используется для reload конфига (nginx -s reload отправляет SIGHUP); SIGSTOP (19) / SIGCONT (18) — pause/resume; SIGCHLD — ребёнок завершился. Процесс может зарегистрировать handler через signal()/sigaction(), кроме SIGKILL и SIGSTOP. `kill -l` — список всех сигналов.
kill -l # список сигналов
kill -TERM 12345 # мягко
kill -9 12345 # SIGKILL — нельзя обработать
kill -HUP $(pgrep nginx) # reload конфига
trap 'echo bye' EXIT # обработчик в bashПара ключ=значение, передаваемая процессу при запуске. Хранится в адресном пространстве процесса; дочерние процессы наследуют env от parent (через execve), но НЕ обратно. Установленная в shell без `export` переменная — только shell variable, в child не попадёт. `export VAR=value` или `VAR=value command` — передать в child. Ключевые: `PATH` (где искать исполняемые), `HOME` (домашняя директория), `USER`, `SHELL`, `LANG`/`LC_ALL` (локаль), `TERM` (тип терминала). Cron и systemd НЕ наследуют env интерактивной сессии — частая ошибка, когда скрипт работает в shell, но не в cron.
echo $PATH # /usr/local/bin:/usr/bin:/bin:...
export DEBUG=1 # для всех child-процессов
env # все env-переменные
printenv PATH # одну
cat /proc/$$/environ # env shell как null-separatedДополнительная directory entry, указывающая на тот же inode, что и оригинальный файл. Не отдельный файл — это второе имя одного и того же файла. Inode хранит link count; при `unlink` (rm) счётчик уменьшается, когда становится 0 и нет открытых FD — блоки данных освобождаются. Все hard links равноправны: нет «оригинала» и «копии». Ограничения: hard link нельзя создать через границу файловой системы (другой inode-пространство), нельзя на каталоги (создал бы циклы в дереве). `ls -l` показывает link count во втором столбце. Применение: дедупликация, backup snapshots (rsync --link-dest).
ln file.txt copy.txt # hard link
ls -li file.txt copy.txt # один inode у обоих
# 12345 -rw-r--r-- 2 user user ... file.txt
# 12345 -rw-r--r-- 2 user user ... copy.txt
# ^ link count = 2
rm file.txt # copy.txt продолжает работатьСпециальный файл (отдельный inode типа `l`), содержащий путь к другому файлу. При обращении ядро прозрачно перенаправляет на target. В отличие от hard link: можно через границы FS, можно на каталоги, может быть broken (target удалён или не существует — dangling symlink), target — это путь (относительный или абсолютный), а не inode-номер. `ls -l` показывает `lrwxrwxrwx ... link -> target`. `readlink` показывает target, `readlink -f` — полный canonical путь. На macOS GNU `readlink -f` отсутствует — нужен `coreutils` через brew или `realpath`.
ln -s /var/log/syslog ~/syslog-link # symlink
ls -l ~/syslog-link
# lrwxrwxrwx ... ~/syslog-link -> /var/log/syslog
readlink ~/syslog-link # /var/log/syslog
readlink -f /bin/sh # canonical (Linux)
realpath /bin/sh # то же, кроссплатф.Директория, в которую «подключается» файловая система. В Linux нет понятия дисков как в Windows (C:/D:) — всё дерево начинается с одного корня `/`. Дополнительные FS (диски, разделы, USB, NFS, tmpfs) монтируются в каталоги: `/`, `/home`, `/boot`, `/mnt/data`, `/media/usb`. `mount` без аргументов показывает активные mounts. `/etc/fstab` — конфиг автомонтирования при boot. Один и тот же раздел можно монтировать в несколько точек (bind mount). `df` показывает usage по mount points. systemd с 245+ использует `.mount` units; `/etc/fstab` всё ещё работает через systemd-fstab-generator.
mount | column -t # все mounts
df -hT # размер + filesystem type
lsblk # блочные устройства как дерево
cat /etc/fstab # автомонтирование
# UUID=... / ext4 errors=remount-ro 0 1
sudo mount /dev/sdb1 /mnt/dataВыводит список файлов и директорий. Без аргументов — текущая. Ключевые опции: `-l` long format (права, owner, размер, mtime, имя), `-a` показать скрытые (начинающиеся с `.`), `-h` human-readable размеры (1.2K вместо 1234), `-t` сортировка по времени модификации (новые первыми), `-r` reverse, `-S` по размеру, `-i` показать inode, `-d` про саму директорию а не её содержимое, `-1` по одному на строку (полезно в pipes). GNU `ls` поддерживает `--color=auto` (по умолчанию в Ubuntu через alias). На macOS — BSD `ls` с теми же базовыми флагами, но без `--time-style`. Modern alternative — `eza` (бывший exa).
ls -la # все файлы, long format
ls -lah # + human sizes
ls -lt | head # 10 свежайших
ls -ld /var/log # инфо о САМОЙ директории
ls -i file.txt # inode номерСменить текущий рабочий каталог (cwd) процесса shell. Built-in команда (не /bin/cd — потому что должна менять состояние самого shell, а не дочернего процесса). Аргументы: `cd dir` — перейти, `cd` без аргументов — в `$HOME`, `cd -` — в предыдущий каталог (хранится в `$OLDPWD`), `cd ..` — на уровень выше, `cd /` — в корень. Bash 4+ поддерживает `cd ~user` — в home другого юзера. Опция `set -o errexit` + `cd nonexistent` упадёт со statusом, без неё — выведет ошибку и продолжит. В скриптах часто используют `cd "$(dirname "$0")"` чтобы перейти в директорию скрипта.
cd /var/log # абсолютный путь
cd ../home # относительный
cd - # туда, где был только что
cd # в $HOME
pushd /etc && popd # стек директорийПечатает абсолютный путь текущего рабочего каталога shell. Built-in. Опции: `-L` (default) — logical, показать путь через symlinks как ввёл пользователь; `-P` — physical, разрешить все symlinks до canonical пути. Полезно в скриптах для самопозиционирования. `$PWD` — переменная shell с тем же значением, `$OLDPWD` — предыдущий каталог (для `cd -`). На production-серверах привычка делать `pwd` перед опасным `rm -rf` спасает от удаления не того, что хотел.
pwd # /home/user/projects/etl
pwd -P # с разрешёнными symlinks
cd /var/log && pwd # /var/log
echo $PWD $OLDPWD # current и previousКопирует файлы и директории. Базовый синтаксис `cp source dest`. Опции: `-r` / `-R` рекурсивно (для директорий), `-p` сохранить permissions/timestamps/owner, `-a` archive mode (= `-dR --preserve=all` — для backup), `-i` interactive (спросить overwrite), `-n` не перезаписывать, `-u` копировать только если source новее, `-v` verbose. По умолчанию cp ПЕРЕЗАПИСЫВАЕТ destination без вопроса (опасно!). Trailing slash на source имеет значение в некоторых случаях. На macOS BSD cp — нет `-T` (no-target-directory). Для больших объёмов лучше `rsync` — поддерживает resume, partial, прогресс.
cp file.txt backup.txt
cp -r dir/ /tmp/ # рекурсивно
cp -a /home /backup/ # с сохранением всего
cp -i *.csv data/ # спросит перед overwrite
cp -uv src/ dest/ # только новее, verboseПеремещает или переименовывает файл/директорию. Внутри одной файловой системы — это атомарная операция: меняется только directory entry, inode и данные остаются. Между разными FS — это `cp + rm`, может быть медленно и НЕ атомарно (при сбое можно потерять данные). Опции: `-i` спрашивать, `-n` не перезаписывать, `-v` verbose, `-u` только если новее, `-b` сделать backup существующего dest. `mv *.csv old/` падает с 'Argument list too long', если файлов десятки тысяч — нужен `find ... -exec mv {} +` или `rsync`.
mv old.txt new.txt # rename
mv file.txt /tmp/ # move
mv *.log archive/ # batch
mv -i src dest # safe (спросит)
mv -v -n src/* dest/ # не перезаписать существующиеУдаляет файлы. Без `-r` НЕ удаляет директории. Опции: `-r` / `-R` рекурсивно, `-f` force (без подтверждения, игнорировать nonexistent), `-i` interactive, `-I` спрашивать один раз перед массовым удалением (>3 файлов или recursive), `-v` verbose, `--preserve-root` (default в GNU) — защита от `rm -rf /`. КРИТИЧНО: rm БЕЗВОЗВРАТНО удаляет (recovery возможен только через filesystem tools, и то редко). На production-серверах используйте `trash-cli` или хотя бы `alias rm='rm -i'`. Никогда `rm -rf $VAR/*` без проверки, что VAR не пуст. `set -u` в bash спасает: упадёт раньше, чем выполнит.
rm file.txt # удалить файл
rm -r dir/ # рекурсивно
rm -rf /tmp/cache # без подтверждений
rm -I *.tmp # спросит один раз
# ЗАЩИТА: всегда echo сначала
echo rm -rf "$DIR"/*Создаёт директорию. Опции: `-p` parents — создать всю цепочку (`mkdir -p a/b/c/d`), не падает если уже существует; `-m MODE` сразу с правами (`mkdir -m 0700 ~/.ssh`); `-v` verbose. Без `-p` падает, если родительская директория не существует, или если каталог уже создан. В скриптах `mkdir -p` идеален для idempotent создания. Permissions новой директории = (0777 & ~umask), обычно 0755. Для конкурентного создания (несколько процессов делают `mkdir -p`) — это race-safe на ext4/xfs.
mkdir data
mkdir -p logs/2026/05 # с предками
mkdir -m 0700 ~/.secrets # сразу 0700
mkdir -pv a/b/c # verbose: показать что создалИзначально — обновить timestamps файла (atime + mtime на текущее время). Если файл не существует — создать пустой. Часто используется именно для создания пустых файлов или для триггера событий (например, marker file для cron). Опции: `-a` только atime, `-m` только mtime, `-t YYYYMMDDhhmm` конкретное время, `-r REF` взять timestamps из REF файла, `-c` не создавать если нет. Не путать с реальным изменением содержимого — touch не пишет данные. Полезно: `touch -t 202405131200 file` — задать конкретный mtime для тестов.
touch newfile.txt # создать пустой
touch *.py # обновить mtime у всех
touch -t 202405010000 old # mtime = 1 мая
touch -r ref.txt other # копировать timestampsСоздаёт ссылки: hard link (default, `ln target name`) или symbolic link (`ln -s target name`). Hard link — вторая directory entry на тот же inode (см. Hard Link). Symlink — отдельный inode с путём (см. Soft Link). Опции: `-s` symbolic, `-f` force (удалить существующий name перед созданием), `-n` для symlinks-на-директории не разыменовывать (заменить, а не положить внутрь), `-r` relative symlink (рассчитать относительный путь от name до target). КЛАССИЧЕСКАЯ ошибка: `ln -s ../path link` где `../path` относительно target, а не cwd — symlink хранит путь как есть.
ln file.txt hard.txt # hard link
ln -s /var/log/syslog ~/log # symlink
ln -sf newtarget existing-link # пересоздать symlink
ls -li hard.txt file.txt # один inode
readlink ~/log # /var/log/syslogПечатает содержимое файла(ов) в stdout. Изначально предназначен для конкатенации (`cat a.txt b.txt > combined.txt`). Опции: `-n` нумеровать строки, `-A` показать non-printable (tabs как `^I`, end-of-line как `$`), `-s` сжать множественные пустые строки. Antipattern: `cat file | grep pattern` — useless use of cat, лучше `grep pattern file` или `< file grep pattern`. Для больших файлов вместо `cat` используют `less` (постранично) или `head/tail`. Heredoc-форма `cat <<EOF ... EOF` — частый идиом для inline-текста в скриптах.
cat /etc/os-release # содержимое
cat -n script.sh # с номерами строк
cat -A weird.txt # видимые tabs и EOL
cat file1 file2 > merged.txt
# heredoc
cat <<EOF > config.ini
[main]
port=8080
EOFПостраничный просмотр текста. В отличие от `more` — поддерживает скроллинг вверх, поиск, не загружает файл целиком (важно для логов на гигабайты). Навигация: Space / Page Down — вниз, b — вверх, /pattern — поиск вперёд, ?pattern — назад, n — следующее совпадение, N — предыдущее, g — в начало, G — в конец, q — выход. F — режим follow (как `tail -f`). `less +F /var/log/syslog` сразу стартует в follow mode. Часто используется через pipe: `command | less`. На многих системах — backend для `man`. Modern alternative — `bat` (`bat file.log`) с подсветкой и встроенным less.
less /var/log/syslog # постранично
less +F /var/log/app.log # follow mode (F для выхода)
dmesg | less # pipe в less
# / поиск, n следующий, q выходПечатает первые N строк (по умолчанию 10) файла или stdin. Опции: `-n N` число строк (или `-N` shortcut: `head -20 file`), `-c N` байт, `-q` не печатать имена файлов в multi-file mode, `-v` всегда печатать. `head -n -5 file` (GNU) — все строки КРОМЕ последних 5. На macOS BSD `head` не поддерживает отрицательные `-n`. Идиоматично: `command | head` для просмотра «начала» вывода, `head -1 file` для первой строки.
head file.csv # первые 10 строк
head -n 5 access.log # первые 5
head -c 100 binary # первые 100 байт
ls -lt | head # 10 свежайших файловПечатает последние N строк (по умолчанию 10). Опции: `-n N` строк, `-c N` байт, `-f` follow — продолжать читать как файл растёт (для логов), `-F` follow с retry (если файл ротируется — переоткрыть), `--pid=PID` остановиться когда процесс завершится. `tail -n +K file` — все строки начиная с K (1-indexed). `tail -f /var/log/app.log | grep ERROR` — классика мониторинга. Современная альтернатива — `multitail` (несколько файлов) или `lnav` (structured logs).
tail file.log # последние 10 строк
tail -n 100 access.log # 100 строк
tail -f /var/log/syslog # live
tail -F app.log # с logrotate
tail -n +2 data.csv # пропустить headerПоиск файлов в дереве каталогов по различным предикатам: имя, размер, mtime, тип, владелец, права, и комбинации. Запускает actions: print (default), exec, delete. Базовый синтаксис: `find PATH [expression]`. Примеры предикатов: `-name '*.log'`, `-type f` (файл) / `-type d` (директория) / `-type l` (symlink), `-mtime -7` (моложе 7 дней), `-size +100M`, `-user nobody`, `-perm 0644`. Actions: `-print` (default), `-delete`, `-exec cmd {} \;` (по одному файлу), `-exec cmd {} +` (батчем — быстрее, как xargs). На macOS BSD `find` — другие флаги для regex, но базовые те же.
find . -name '*.csv'
find /var/log -mtime -1 -type f # за сутки
find . -size +100M # больше 100MB
find . -name '*.tmp' -delete
find . -type f -exec gzip {} + # gzip каждогоБыстрый поиск файлов по имени через предварительно построенную базу (`/var/lib/plocate/plocate.db` в Ubuntu 26.04). Намного быстрее `find` (миллисекунды против минут), но: показывает то, что было на момент последнего обновления базы (cron-job `updatedb` обычно раз в сутки); не умеет фильтровать по mtime/size/owner; может показать файлы, к которым у вас нет прав (хотя plocate уважает permissions). Опции: `-i` case-insensitive, `-r` regex, `-c` count, `-l N` limit. На Ubuntu — `plocate` (replacement для mlocate), быстрее за счёт сжатой БД. `sudo updatedb` обновить вручную.
locate nginx.conf # все файлы с этим именем
locate -i Readme # case-insensitive
locate -c '*.log' # сколько штук
sudo updatedb # обновить базуПоиск строк, соответствующих регулярному выражению. Базовый синтаксис: `grep [opts] PATTERN [FILE...]`. Опции: `-i` case-insensitive, `-v` invert (показать НЕ совпадающие), `-n` номера строк, `-r` рекурсивно по каталогу, `-l` только имена файлов с совпадением, `-c` count, `-w` целые слова, `-E` ERE (extended regex, как egrep), `-F` fixed string (как fgrep, для буквального поиска без regex), `-P` Perl regex (PCRE, поддерживает lookahead/lookbehind), `-A N` / `-B N` / `-C N` контекст (after/before/around). На macOS BSD grep ограниченнее GNU — `-P` нет, нужно ставить gnu-grep через brew. Modern: `ripgrep` (rg) — быстрее и удобнее.
grep ERROR /var/log/syslog
grep -rni 'todo' src/ # рекурсивно, case-insens, с номерами
grep -v '^#' config.ini # без комментариев
grep -E '^(ERROR|WARN)' log
grep -c ERROR app.log # счётчикПотоковый редактор: применяет команды к каждой строке stdin/файла. Самая частая команда — substitute: `sed 's/pattern/replacement/flags'` (flags: g — все вхождения в строке, i — case-insensitive, N — N-ое вхождение). Другие: `d` delete, `p` print, `s` substitute, addresses `1,5` или `/pattern/`. `-i` — in-place edit (опасно без backup!). КЛАССИЧЕСКАЯ DIFF: GNU sed (Linux) — `sed -i 's/a/b/' file`, BSD sed (macOS) — `sed -i '' 's/a/b/' file` (обязательный пустой backup-extension). По умолчанию BRE (Basic Regex), `-E` (или `-r` в GNU) для ERE. Используется чаще для simple substitutions; для сложного — awk или Python.
sed 's/old/new/' file # замена первого в каждой строке
sed 's/old/new/g' file # все вхождения
sed -i.bak 's/foo/bar/g' f # in-place с backup
sed -n '5,10p' file # печатать только строки 5-10
sed '/^#/d' config # удалить комментарииМощный язык обработки структурированного текста, особенно колоночного. Программа awk состоит из пар pattern { action }. Для каждой строки awk разбивает её на поля (по разделителю FS, default — whitespace) и доступ через `$1`, `$2`, ..., `$NF` (last field), `$0` — вся строка. Встроенные переменные: NR (номер строки), NF (число полей), FS / OFS (input/output field sep). Спецблоки: BEGIN { ... } до обработки, END { ... } после. На Linux обычно gawk (GNU awk); на macOS — BSD awk и `gawk` через brew. Используется для агрегации логов, парсинга CSV/TSV, преобразований формата.
awk '{print $1}' file # первое поле
awk -F, '{print $3}' data.csv # CSV
awk 'NR>1 {sum+=$2} END {print sum}' f # сумма колонки 2
awk '/ERROR/ {print $4}' log
awk -F: '$3 < 100 {print $1}' /etc/passwdИзвлекает части каждой строки: байты (`-b`), символы (`-c`) или поля (`-f` с разделителем `-d`). Базовый use case — быстро вырвать колонку из delimited файла. Синтаксис диапазонов: `-f 1` (одно поле), `-f 1,3` (несколько), `-f 1-3` (диапазон), `-f 2-` (со 2 до конца). `-d` принимает один символ как delimiter (нельзя regex или multi-char — для этого awk). По сравнению с awk: cut проще и быстрее для простых extractions, но не поддерживает условные правила. Для CSV с запятыми внутри кавычек cut не подойдёт — нужен правильный CSV parser (awk с FPAT, Python, miller).
cut -d: -f1 /etc/passwd # имена пользователей
cut -d, -f1,3 data.csv # 1 и 3 поля
cut -c1-10 file # первые 10 символов
echo 'a:b:c:d' | cut -d: -f2-3 # b:cСортирует строки. Default — лексикографически по всей строке. Опции: `-n` числовая сортировка, `-h` human-numeric (1K < 1M < 1G), `-r` reverse, `-u` unique (= sort + uniq), `-k N` по N-ому полю, `-t SEP` разделитель полей, `-V` version sort (1.2.10 после 1.2.9), `-R` random shuffle, `-c` check sorted, `-m` merge already-sorted. Для больших файлов sort использует внешнюю сортировку (с временными файлами в `/tmp`, см. `-T` для смены). Установка `LC_ALL=C` ускоряет sort (байтовое сравнение вместо locale-aware) и часто меняет результат для не-ASCII.
sort file
sort -n numbers.txt # числовая
sort -rn -k2 -t, data.csv # по 2 полю числово reverse
sort -u file # уникальные
sort -h sizes.txt # 1K, 2M, 1G
LC_ALL=C sort huge.txt # быстрееУдаляет смежные дубликаты строк (или показывает только их). КЛАССИЧЕСКАЯ ловушка: uniq работает только с СОСЕДНИМИ строками — для удаления всех дубликатов нужно `sort | uniq` (или `sort -u`). Опции: `-c` count (сколько раз встречалась), `-d` только дубликаты, `-u` только уникальные (встретились ровно раз), `-i` case-insensitive, `-f N` пропустить N полей при сравнении, `-w N` сравнивать только первые N символов. Классическая идиома: `sort | uniq -c | sort -rn` — топ-N самых частых строк (например, IP в логе).
sort access.log | uniq # удалить дубликаты
sort | uniq -c | sort -rn # топ по частоте
sort | uniq -d # только дубли
cut -d, -f1 data.csv | sort -u # уникальные значения колонки 1Считает строки (`-l`), слова (`-w`), байты (`-c`), символы (`-m`), длину самой длинной строки (`-L`). По умолчанию выводит lines, words, bytes и имя файла. `wc -l file.csv` — частая операция для подсчёта строк в CSV (с учётом header — `wc -l file && head -1 file` для проверки). Для большого числа файлов: `wc -l *.log` даёт total в конце. На macOS поведение схоже с GNU. Антипаттерн: `cat file | wc -l` — useless cat, лучше `wc -l < file` или `wc -l file`.
wc file.txt # 5 20 120 file.txt
wc -l *.csv # построчно с total
wc -l < access.log # без имени файла
wc -c file # размер в байтах
find . -name '*.py' | wc -l # сколько .py файловЗаменяет, удаляет или сжимает символы. Работает только со stdin (не принимает имена файлов!). Базовый: `tr 'SET1' 'SET2'` — каждый символ из SET1 заменяется на соответствующий из SET2. Опции: `-d` удалить символы SET1, `-s` сжать повторы SET1 в один, `-c` complement (НЕ из SET1), `-t` truncate SET1 до длины SET2. Спецсимволы: `\n`, `\t`, `[:upper:]`, `[:lower:]`, `[:digit:]`, `[:space:]`. Классика: `tr '[:upper:]' '[:lower:]'` — uppercase в lowercase; `tr -d '\r'` — убрать CRLF из Windows-файла; `tr -s ' '` — сжать множественные пробелы.
echo HELLO | tr A-Z a-z # hello
tr -d '\r' < windows.txt > unix.txt # убрать CR
tr -s ' ' < file # сжать пробелы
echo 'a1b2c3' | tr -d '0-9' # abc
tr ',' '\n' < csv # запятые в newlinesОбъединяет соответствующие строки из нескольких файлов через delimiter (по умолчанию tab). Противоположность `cut`. Опции: `-d SEP` разделитель (можно несколько символов в кружок: `-d',;'`), `-s` сериально (все строки одного файла в одну, через delim). `paste file1 file2` — построчно склеить. Полезно для построения CSV из отдельных колонок или объединения файлов с метриками. Альтернативы: `awk` для более сложного, `join` для join по ключу.
paste names.txt scores.txt # tab-separated
paste -d, names.txt scores.txt # CSV
paste -s -d, file # все строки в одну
paste -d: <(cut -d: -f1 /etc/passwd) <(cut -d: -f5 /etc/passwd)Сравнивает два ОТСОРТИРОВАННЫХ файла построчно. Выводит три колонки: только в file1, только в file2, общие. Опции `-1`, `-2`, `-3` подавляют соответствующую колонку. ОБЯЗАТЕЛЬНОЕ требование — оба файла должны быть отсортированы (одинаковым образом, обычно `sort` без аргументов). `comm -12 a b` — пересечение, `comm -23 a b` — только в a, `comm -13 a b` — только в b. По сравнению с `diff`: comm покажет именно set-операции, diff — построчный diff с контекстом.
sort a.txt > a.sorted
sort b.txt > b.sorted
comm a.sorted b.sorted # 3 колонки
comm -12 a.sorted b.sorted # intersection
comm -23 a.sorted b.sorted # только в a
# через process substitution без temp файлов
comm -12 <(sort a) <(sort b)Построчное сравнение двух файлов с выводом изменений. Форматы: default (ed-style), `-u` unified diff (как в Git, чаще всего), `-c` context, `-y` side-by-side. Опции: `-r` рекурсивно для директорий, `-q` brief (только factом отличия), `-i` ignore case, `-w` ignore whitespace, `-B` ignore blank lines. Возвращает exit code 0 (одинаково), 1 (различаются), 2 (ошибка) — удобно в скриптах. Альтернативы: `colordiff` (с цветом), `delta` (modern, gitlike), `meld` (GUI), `vimdiff`.
diff a.txt b.txt # default format
diff -u a.txt b.txt # unified (как в патчах)
diff -r dir1/ dir2/ # рекурсивно
diff -q a b # только факт отличия
diff <(sort a) <(sort b) # без temp файловЧитает stdin и пишет одновременно в stdout И в файл(ы). Имя от Y-образного фитинга (T): один вход, два выхода. Опции: `-a` append (по умолчанию overwrite). Классический use case — посмотреть вывод команды И сохранить его одновременно: `make 2>&1 | tee build.log`. Идиома для sudo-записи в файл, требующий root: `echo 'line' | sudo tee /etc/file > /dev/null` (потому что `>` в `sudo cmd > file` редиректит уже от текущего юзера). `tee -a` — append.
make 2>&1 | tee build.log # вывод и в консоль, и в файл
echo line | sudo tee -a /etc/hosts
ls | tee file1 file2 file3 # в несколько файлов
command | tee out.log | grep ERRORSnapshot процессов в системе. Имеет две стилистики опций: BSD (без дефиса: `ps aux`) и UNIX/POSIX (с дефисом: `ps -ef`). Самые частые: `ps aux` (все процессы всех юзеров с подробностями: USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND), `ps -ef` (другой формат с PPID), `ps -ef --forest` или `ps auxf` — дерево. Опции: `-o COL1,COL2` — кастомный вывод (`ps -o pid,user,cmd`), `-p PID` — конкретный процесс, `-u USER` — фильтр по юзеру. Для интерактивного мониторинга — `top` / `htop`.
ps aux # все процессы
ps -ef --forest # дерево
ps -o pid,user,%cpu,cmd | sort -k3 -rn | head # топ CPU
ps -u nobody # процессы юзера
ps -p $$ # текущий shellИнтерактивный мониторинг процессов. Обновляется в реальном времени. Показывает: load average, uptime, число процессов, CPU usage (user/sys/idle/iowait), память (total/free/used/buff/cache), swap, и список процессов с PID, USER, PR, NI, VIRT, RES, SHR, %CPU, %MEM, TIME, COMMAND. Hotkeys: P sort by CPU, M by memory, T by time, k kill (запросит PID), q quit, 1 раскрыть CPU по ядрам, c полные argv. На macOS — другой top (поддерживает -o), полностью совместимый htop через brew.
top # запустить
# внутри: P (CPU), M (memory), k <PID>, q
top -b -n 1 | head -20 # один snapshot (для скриптов)
top -u www-data # конкретный юзерModern alternative для `top` — цветной интерфейс, mouse support, дерево процессов через F5, фильтр F4, поиск F3. Ставится отдельно (`apt install htop`). Опции: `htop -p PID1,PID2` отслеживать конкретные, `-u USER` фильтр, `-t` дерево с начала. Hotkeys внутри: F5 tree, F6 sort, F9 kill (выбрать signal из меню), F3 search, Space mark, U unmark. На macOS работает через brew install htop. Похожие: `btop` (ещё современнее, с графиками), `glances` (cross-platform Python).
htop # интерактивно
htop -u nobody # юзер
htop -p $(pgrep -d, nginx) # все nginx процессыОтправляет сигнал процессу. Синтаксис: `kill [-SIGNAL] PID`. По умолчанию — SIGTERM (15), graceful shutdown. `kill -9 PID` или `kill -KILL PID` — SIGKILL, мгновенно (нельзя обработать, нет cleanup). Сигналы по имени или номеру: `kill -HUP $(pgrep nginx)` — reload nginx. `kill -l` — список всех сигналов. Built-in в bash, но также `/bin/kill` существует. Связанные: `pkill` (по имени или паттерну: `pkill -f python`), `killall` (точно по имени), `kill %1` (по job ID в bash).
kill 12345 # SIGTERM
kill -9 12345 # SIGKILL
kill -HUP $(pgrep nginx) # reload
kill -l # список signals
kill %1 # job 1
pkill -9 -f 'python etl.py'Убивает все процессы по имени (НЕ по PID). Полезно когда не хочется искать PID через ps. Опции: `-9` SIGKILL, `-u USER` только процессы юзера, `-i` interactive (спросить), `-r` имя как regex, `-w` ждать завершения. ВНИМАНИЕ: на Solaris `killall` убивает ВСЕ процессы (отсюда мем «не делай killall на Solaris»). В Linux/BSD безопасен. На macOS из коробки. Часто заменяется на `pkill` (более гибкий — поддерживает full cmdline matching с `-f`).
killall firefox # все firefox процессы
killall -9 stuck-process
killall -i node # спросит про каждый
killall -u nobody # все процессы nobodyПоказывает background и stopped задачи текущего shell. Built-in. Задачи имеют job ID (`[1]`, `[2]`), отличный от PID. Используется с `&` (запустить в фоне), `Ctrl+Z` (приостановить), `fg %N` (вывести на foreground), `bg %N` (продолжить в фоне). Опции: `-l` показать PID, `-p` только PID, `-r` running, `-s` stopped. Задачи живут только пока shell открыт; для долгоживущих фоновых задач — `nohup`, `disown`, `screen`, `tmux` или systemd-сервис.
long-running-cmd & # в фон
jobs -l # с PID
# Ctrl+Z приостановить foreground
fg %1 # вернуть
bg %2 # продолжить в фонеЗапускает команду, игнорирующую SIGHUP. Полезно когда нужно запустить долгий процесс через SSH и закрыть терминал — без nohup при закрытии TTY дочерним процессам отправляется SIGHUP и они умирают. По умолчанию nohup редиректит stdout/stderr в `nohup.out` в cwd (если оно writable, иначе в `~/nohup.out`). Идиома: `nohup long-cmd > /tmp/out.log 2>&1 &`. Альтернативы: `disown` (отвязать от shell), `setsid` (новая сессия), tmux/screen (виртуальный терминал), systemd-run (создать ad-hoc systemd unit).
nohup python etl.py > etl.log 2>&1 &
nohup ./backup.sh & # вывод в nohup.out
# проверить что отвязалось
ps -ef | grep etl.py
# disown после запуска
long-cmd & disownОператор shell — запустить команду в фоне (background). Shell не ждёт завершения, возвращает prompt сразу. `$!` — PID последнего background процесса. После запуска можно `wait $PID` дождаться, `kill $PID` убить, `jobs` посмотреть. ВНИМАНИЕ: фоновый процесс по-прежнему привязан к терминалу — при exit shell ему пошлётся SIGHUP, если не настроен `huponexit` или не использовали nohup/disown. `&&` (не путать с `&`) — это другое: AND, выполнить если предыдущая команда успешна.
long-cmd & # в фон
echo $! # PID
wait # подождать всех фоновых
wait $! # последнего
# несколько параллельных
cmd1 & cmd2 & cmd3 & waitВозвращает background или stopped задачу на foreground. Built-in. Без аргументов — последнюю (current) задачу; `fg %N` — конкретную по job ID; `fg %name` — по началу имени команды. После fg задача снова получает stdin/stdout терминала и блокирует prompt. Часто используется после `Ctrl+Z` (suspend foreground task — она становится stopped в jobs) — `fg` чтобы продолжить там же.
long-cmd &
fg # последняя в фон
fg %2 # job 2
fg %vim # job, начинающийся на vim
# Ctrl+Z приостановить vim, делать что-то, потом fgПродолжает stopped задачу в background. Built-in. Поток управления: запустили команду в foreground -> Ctrl+Z (suspend -> stopped) -> `bg` (продолжить в фоне). Альтернативно: можно сразу `cmd &` без Ctrl+Z. `bg %N` — конкретную stopped задачу. После bg задача отвязана от stdin (если попробует читать — получит SIGTTIN и остановится снова). Полезно когда запустил что-то долгое в foreground и хочется параллельно работать без рестарта.
long-build-script
# случайно в foreground, ждёт долго
# Ctrl+Z
# [1]+ Stopped long-build-script
bg # продолжить в фоне
jobs # [1]+ Running long-build-script &Инструмент для передачи данных по сетевым протоколам (HTTP/HTTPS, FTP, SCP, SFTP, IMAP и др.). Универсальный HTTP-клиент в CLI. Опции: `-X METHOD` (GET/POST/PUT/DELETE), `-H 'Header: value'` заголовки, `-d 'data'` POST body (`--data-raw`, `--data-binary`, `--data-urlencode`), `-F` multipart, `-o file` save to file, `-O` save as remote name, `-L` follow redirects, `-s` silent (без progress), `-S` показать ошибки даже с -s, `-w '%{http_code}'` шаблон вывода, `-u user:pass` basic auth, `-k` ignore SSL errors (DANGER на проде). Часто пара `curl -fSL` — fail on HTTP errors, silent но с errors, follow redirects.
curl https://api.github.com/users/octocat
curl -fSLo out.zip URL
curl -X POST -H 'Content-Type: application/json' \
-d '{"key":"val"}' https://api.example.com
curl -w '%{http_code}\n' -o /dev/null -s URLАльтернатива curl для скачивания файлов. Проще curl для типовых задач: `wget URL` сразу сохраняет в файл с правильным именем. Поддерживает recursive download (`-r`, для зеркалирования сайтов), `-c` continue (resume прерванной загрузки), `--limit-rate=200k` ограничение скорости, `-q` quiet, `--no-check-certificate` ignore SSL. По сравнению с curl: wget лучше для рекурсивных загрузок и mirroring, curl универсальнее для API. На macOS не предустановлен (brew install wget). В скриптах чаще встречается `curl -fSLo`.
wget https://example.com/file.tar.gz
wget -c URL # resume
wget -r --no-parent URL # mirror
wget --limit-rate=500k URL # rate limit
wget -i urls.txt # из файла со списком URLЗашифрованное удалённое подключение к серверу. Дефолтный порт 22 (TCP). Аутентификация: по паролю (плохо для prod) или по key pair (RSA, ECDSA, Ed25519). Базовый: `ssh user@host`. Опции: `-p PORT` порт, `-i KEYFILE` приватный ключ, `-X` X11 forwarding, `-L LOCAL:HOST:REMOTE` local port forwarding, `-D PORT` SOCKS proxy, `-J jump-host` через bastion, `-N` без shell (только tunnel), `-f` в фон, `-o Option=val`. Config: `~/.ssh/config` со стенками `Host alias / HostName / User / Port / IdentityFile / ProxyJump`. Известные хосты: `~/.ssh/known_hosts` — fingerprints для защиты от MITM. На Ubuntu 26.04 — OpenSSH 9.9+.
ssh user@host
ssh -p 2222 -i ~/.ssh/id_ed25519 user@host
ssh -L 5432:db.internal:5432 bastion # tunnel
ssh -J bastion user@private-host # jump
# ~/.ssh/config
# Host prod-airflow
# HostName 10.0.0.5
# User deployКопирование файлов по SSH-протоколу. Синтаксис как у cp: `scp [opts] source dest`, где source/dest может быть локальный путь или `user@host:path`. Опции: `-r` рекурсивно, `-P PORT` (большой P — отличается от ssh!), `-i KEY` ключ, `-p` preserve timestamps, `-C` compress, `-3` через локалку при copy между двумя remote. ВАЖНО: OpenSSH 9.0+ default switched scp to use SFTP protocol под капотом — старые quirks с remote globbing исчезли. Для production файл-синхронизации лучше использовать `rsync` (incremental, resume, прогресс).
scp file.txt user@host:/tmp/
scp -r dir/ user@host:/data/
scp -P 2222 user@host:/var/log/app.log .
scp user1@h1:/data/f user2@h2:/data/ # remote -> remoteИнкрементальная синхронизация файлов: передаёт только различия (через rolling checksum алгоритм). Намного эффективнее scp для повторных синхронизаций. Опции: `-a` archive (= `-rlptgoD`, рекурсивно + symlinks + permissions + timestamps + owner + group + devices), `-v` verbose, `-z` compression, `-h` human-readable, `-P` = `--partial --progress` (resume + прогресс), `--delete` удалить из dest то, чего нет в source (опасно!), `--dry-run` / `-n` симуляция, `--exclude PATTERN`. КЛЮЧЕВАЯ ловушка: `rsync src/ dest/` (с trailing slash) — копирует содержимое src В dest; `rsync src dest/` (без trailing slash) — копирует папку src ВНУТРЬ dest.
rsync -avz src/ user@host:/backup/
rsync -avP --delete --dry-run src/ dest/ # симуляция
rsync -av --exclude='*.pyc' --exclude='.git' src/ dest/
rsync -av -e 'ssh -p 2222' src/ user@host:/dest/Современная замена netstat — показывает сокеты (TCP, UDP, Unix). Часть iproute2. Опции: `-t` TCP, `-u` UDP, `-l` listening, `-n` numeric (без DNS resolve, быстрее), `-p` показать процессы, `-a` все (вместе с established). Классическая идиома `ss -tlnp` — какие TCP-порты слушаются и кем. По сравнению с netstat: ss быстрее (читает напрямую из netlink, а не парсит /proc/net), современнее, чаще доступен на свежих дистрибутивах. На macOS используется `lsof -i` или `netstat`.
ss -tlnp # TCP listening + процессы
ss -tunap # все TCP+UDP с PID
ss -s # summary
ss state established # только established
ss -t state time-wait # TIME_WAIT соединенияDNS-резолвер из BIND. Показывает запись DNS для домена. Базовый: `dig example.com` (default A record), `dig example.com MX` (mail), `dig example.com AAAA` (IPv6), `dig example.com NS` (nameservers), `dig example.com TXT`. Опции: `+short` — только ответ без metadata, `@server` — использовать конкретный DNS-сервер (`@8.8.8.8`), `+trace` — пройти DNS-дерево с корня. Альтернативы: `host` (проще), `nslookup` (deprecated в пользу dig), `getent hosts` (использует nsswitch). На macOS dig из коробки.
dig example.com
dig +short example.com
dig example.com MX
dig @8.8.8.8 example.com # через Google DNS
dig +trace example.com # пошаговоОтправляет ICMP echo request, измеряет latency и packet loss. Базовый `ping host`. Опции: `-c N` отправить N пакетов и выйти (без -c шлёт бесконечно), `-i SEC` интервал между пакетами, `-W SEC` timeout, `-s SIZE` размер payload, `-q` quiet (только summary). На многих cloud-провайдерах ICMP блокируется firewall — отсутствие ответа не всегда означает, что хост недоступен. Для TCP-проверки используют `nc -zv host port` или `curl -I`. На Linux обычный ping (без sudo) использует unprivileged ping sockets (раньше требовался setuid).
ping -c 4 google.com # 4 пакета и выйти
ping -i 0.2 -c 100 host # быстрый flood (нужны права)
ping -q -c 10 host # summary
# для cron/scripts
ping -c 1 -W 2 host && echo UP || echo DOWNПоказывает маршрут пакетов до хоста — список hop'ов с RTT для каждого. Принцип: посылает пакеты с возрастающим TTL (1, 2, 3, ...); каждый router декрементирует TTL и при 0 отвечает ICMP Time Exceeded — так выясняется адрес каждого hop'а. Опции: `-n` без DNS resolve (быстрее), `-T` TCP (через порт 80 — обходит файрволы блокирующие UDP/ICMP), `-I` ICMP. На Linux часто используется `mtr` (combined ping + traceroute, real-time). На macOS — `traceroute` из коробки. В Windows — `tracert`.
traceroute google.com
traceroute -n -T google.com # TCP, без DNS
mtr google.com # real-time альтернатива
mtr --report -c 100 host # отчётШвейцарский нож сетевых утилит — читает/пишет в TCP/UDP сокеты. Use cases: проверка открыт ли порт (`nc -zv host port`), простой listener (`nc -l 9999`), передача файла (`nc -l 9999 > file` на receiver, `nc host 9999 < file` на sender), banner grabbing. Варианты: BSD netcat (default на macOS и многих Linux), GNU netcat, ncat (от nmap, расширенный). Опции (могут различаться по реализациям): `-l` listen, `-p PORT` порт source (BSD), `-z` zero-IO (только проверить порт), `-v` verbose, `-u` UDP, `-w SEC` timeout, `-N` close stdin при EOF.
nc -zv host.example.com 443 # порт открыт?
nc -l 9999 # listener
nc host 9999 # подключиться
# передача файла
# receiver: nc -l 9999 > received.bin
# sender: nc host 9999 < file.binПервая строка скрипта, начинающаяся с `#!` (hash + bang), указывающая ядру, какой интерпретатор запустить. Ядро при `execve()` читает первые байты файла; если `#!`, парсит до newline и выполняет `interpreter [optional-arg] script-path`. Примеры: `#!/bin/bash` (явный путь), `#!/usr/bin/env bash` (через env — найдёт bash в $PATH, портабельнее между Linux/macOS/BSD), `#!/usr/bin/env python3`, `#!/usr/bin/awk -f`. БЕЗ shebang скрипт всё равно может выполниться (shell сам запустит как sh-скрипт), но это уязвимо: на macOS sh = bash, в Debian sh = dash — поведение различается. Правило: явный shebang всегда.
#!/usr/bin/env bash # портабельный
#!/bin/bash # явный
#!/bin/sh # POSIX-только
#!/usr/bin/env python3
# проверить какой интерпретатор
head -1 script.shИменованное значение. В bash: `VAR=value` (БЕЗ пробелов вокруг `=` — иначе bash попытается выполнить VAR как команду!), доступ `$VAR` или `${VAR}` (обязательно фигурные если есть символы после имени). Quoting: `"$VAR"` — expansion с сохранением пробелов; `'$VAR'` — литерал, без expansion; `$VAR` без кавычек — word splitting + glob expansion (опасно). Параметрические expansions: `${VAR:-default}` (если пусто/unset — default), `${VAR:=default}` (то же + присвоить), `${VAR:?error}` (упасть с error), `${#VAR}` (длина), `${VAR%suffix}` / `${VAR#prefix}` (отрезать). Без `export` — только в текущем shell.
NAME="Lev" # без пробелов!
echo "Hello, $NAME"
echo "${NAME}_suffix"
FOO=${VAR:-default} # default value
FOO=${VAR:?error} # упасть если unset
echo ${#NAME} # 3
export PATH=$PATH:/opt/binBash поддерживает индексированные массивы (с bash 3+) и ассоциативные (с bash 4+). Индексированный: `arr=(one two three)` или `arr[0]=one; arr[1]=two`. Доступ: `${arr[0]}` (элемент), `${arr[@]}` (все элементы, word-split), `${arr[*]}` (все одной строкой через IFS), `${#arr[@]}` (количество). Ассоциативный (нужен `declare -A`): `declare -A map; map[key]=value; echo ${map[key]}`. ВАЖНО: `"${arr[@]}"` в кавычках — каждый элемент как отдельное слово (правильно для аргументов); без кавычек — word splitting по пробелам внутри элементов (ломается на путях с пробелами).
arr=(apple banana cherry)
echo ${arr[0]} # apple
echo ${arr[@]} # все
echo ${#arr[@]} # 3
for x in "${arr[@]}"; do echo $x; done
# associative
declare -A ages
ages[alice]=30
ages[bob]=25
echo ${ages[alice]}Именованный блок кода. Синтаксис: `name() { commands; }` или `function name { commands; }` (второй — bash-only). Аргументы доступны как `$1`, `$2`, ..., `$@` (все, word-split), `$*` (все одной строкой), `$#` (количество). `return N` устанавливает exit code функции (0-255), НЕ возвращает значение (для этого — echo + `result=$(func)`). Локальные переменные: `local var=value` внутри функции (без local — глобальные, что обычно плохо). Функции можно экспортировать в дочерние shell: `export -f func`. Часто используются для DRY в скриптах: проверки, логирование, cleanup.
log() {
echo "[$(date '+%H:%M:%S')] $*" >&2
}
greet() {
local name=$1
echo "Hello, $name"
}
greet "World"
result=$(greet "Alice")Целое число 0–255, которое процесс возвращает родителю при завершении. По соглашению: 0 — успех, любое ненулевое — ошибка. Конкретные коды: 1 — generic error, 2 — misuse, 126 — нельзя выполнить (permissions), 127 — command not found, 128+N — убит сигналом N (`kill -9` = exit 137), 130 — Ctrl+C (128+SIGINT). Доступ в bash: `$?` после команды. В скриптах используется в `if cmd; then ...; fi`, `cmd && next` (запустить next если cmd успешна), `cmd || fallback`. `set -e` (errexit) автоматически прерывает скрипт при ненулевом exit, КРОМЕ команд в `if`, `while`, перед `||`, `&&`.
ls /nonexistent
echo $? # 2
true; echo $? # 0
false; echo $? # 1
if grep -q ERROR log; then
echo "errors found"
fi
command1 && command2 || echo failedСпециальная переменная bash, определяющая, по каким символам shell делит строки на «слова» при word splitting (после expansion переменных) и при `read`. Default: `IFS=$' \t\n'` (пробел, tab, newline). Установка `IFS=,` заставит word splitting по запятым. Идиоматический pattern для чтения файла построчно: `while IFS= read -r line; do ...; done < file` — пустой IFS отключает обрезку, `-r` отключает обработку backslash. Локальный override: `IFS=, read -ra arr <<<"$csv_line"` — разбить CSV-строку в массив. Восстановление: `OLD_IFS=$IFS; IFS=,; ...; IFS=$OLD_IFS` или просто `unset IFS`.
echo "$IFS" | od -c # обычно ' \t \n'
# CSV в массив
IFS=, read -ra fields <<<"a,b,c"
echo ${fields[1]} # b
# Чтение файла построчно
while IFS= read -r line; do
echo "$line"
done < file.txtСпособ передать многострочный текст в stdin команды inline. Синтаксис: `cmd <<DELIMITER` ... текст ... `DELIMITER` (на отдельной строке). Внутри — нормальная expansion переменных и command substitution. `<<-DELIMITER` (с тире) — игнорировать leading tabs (для indented scripts). `<<'DELIMITER'` (в кавычках) — БЕЗ expansion, литеральная строка. Сокращённый here-string: `cmd <<<"string"` — одна строка в stdin. Часто используется: inline-конфиги (`cat > file <<EOF ... EOF`), inline-SQL (`psql <<SQL ... SQL`), inline-Python (`python <<'PY' ... PY`).
cat <<EOF > config.ini
[server]
port=$PORT
host=$HOSTNAME
EOF
# Без expansion
cat <<'EOF'
$VAR is literal
EOF
# here-string
wc -w <<<"hello world" # 2Канонический prelude production-grade bash-скрипта. `-e` (errexit) — выйти при первой команде с ненулевым exit code (кроме if/while/||/&&). `-u` (nounset) — упасть при обращении к unset-переменной (ловит typos: `$USR` вместо `$USER` падает вместо тихого пустого значения, что критично в `rm -rf $UNDEF/`). `-o pipefail` — exit code pipeline равен последнему ненулевому в цепочке (без него `false | true` возвращает 0, прячет ошибку первой команды). Дополнительно часто: `IFS=$'\n\t'` (защита от пробелов в путях), `shopt -s nullglob` (пустой glob — пустой массив, а не литеральная строка `*.csv`).
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# теперь:
echo "$UNDEF" # упадёт с error
false | true # упадёт (pipefail)
rm /nonexistent # упадёт (errexit)