head: первые N строк или байт
$ head file # первые 10 строк (default)
$ head -n 20 file # первые 20 строк
$ head -n 5 file # первые 5
$ head -c 1024 file # первые 1024 байта
$ head -n -3 file # все, кроме последних 3 (отрицательное число!)
head оптимален: открывает файл, читает N строк, закрывает и завершается. На файле в 1TB он прочитает только первые ~10KB.
$ time head -n 10 huge.log
real 0m0.003s # моментально
head -c — для бинарных файлов
$ head -c 4 image.png | xxd
00000000: 8950 4e47 .PNG
# Первые 4 байта PNG = magic bytes \x89PNG
Полезно для file type detection (вместо file команды) и для quick-sample data files.
tail: последние N строк или байт
$ tail file # последние 10 строк
$ tail -n 50 log.log # последние 50
$ tail -n +5 file # с 5-й строки до конца (НЕ путать с -n 5)
tail -n +N: skip first N-1 lines
# Пропустить header CSV
$ tail -n +2 data.csv | head
# data starts here, без заголовка
# Пропустить первые 100 строк (например, лицензионное соглашение в начале файла)
$ tail -n +101 README.txt
Знак + критичен: -n 5 это «последние 5 строк», -n +5 это «с 5-й строки до конца».
tail -f: follow
Самая полезная фишка tail для DE:
$ tail -f /var/log/airflow/scheduler.log
2026-05-13 12:34:56 INFO loading DAG sync_orders
2026-05-13 12:34:57 INFO loading DAG load_dim_users
# курсор остаётся, новые строки появляются в реальном времени...
-f (--follow) держит файл открытым и выводит новые строки по мере их появления. Это watch-режим для логов. Прервать — Ctrl+C.
Под капотом: tail делает lseek к концу файла, потом в цикле read() и inotify_wait() (Linux) или polling (BSD).
tail -F: follow with re-open
Различия -f vs -F:
$ tail -f /var/log/app.log
# Когда log rotation удалит app.log и создаст новый —
# tail продолжит читать СТАРЫЙ inode, который больше не растёт.
# Новых строк не увидишь.
$ tail -F /var/log/app.log
# tail -F отслеживает имя файла. Если файл исчез/пересоздался —
# tail откроет новый файл и продолжит.
-F — must-have для production логов под logrotate. Если log утром был ротирован, -f подвиснет на старом inode, -F подцепит новый файл автоматически.
# Эквивалент:
$ tail --follow=name --retry /var/log/app.log
tail -f и пайпы
# Real-time filter:
$ tail -f /var/log/api.log | grep ERROR
# С контекстом:
$ tail -f /var/log/api.log | grep -C 2 ERROR
ВНИМАНИЕ: Внимание: grep в pipeline буферизует output. Если данные приходят медленно, ты увидишь их с задержкой. Решение — --line-buffered:
$ tail -F /var/log/app.log | grep --line-buffered ERROR
Или stdbuf -oL grep ... (force line-buffered). Иначе grep будет копить ~4KB прежде чем выводить.
DE-кейсы tail -F
1. Watch Airflow scheduler
$ tail -F /var/log/airflow/scheduler.log | grep -E '(ERROR|Task)'
2. Multi-file watch
$ tail -F /var/log/airflow/*.log
==> /var/log/airflow/scheduler.log <==
INFO loading DAG ...
==> /var/log/airflow/worker.log <==
ERROR connection timeout
==> /var/log/airflow/dag_processor.log <==
INFO parsing DAGs...
tail -F на множестве файлов добавляет header ==> filename <== перед каждой группой строк. Удобно для одновременного мониторинга разных компонентов.
3. Tail с компрессированными логами
$ zcat /var/log/airflow/scheduler.log.5.gz | tail -100
zcat декомпрессирует на лету, tail берёт последние 100 строк. Альтернатива: tail -100 <(zcat file.gz).
tee: развилка stdout
tee (от “T-fitting” в водопроводе) — копирует stdin в stdout И файл одновременно:
$ command | tee output.log
# command's stdout -> output.log AND видимо на экране
$ ls -l | tee files.txt
total 24
-rw-r--r-- 1 levo levo 321 May 13 README.md
-rw-r--r-- 1 levo levo 1024 May 13 data.csv
$ cat files.txt
total 24
-rw-r--r-- 1 levo levo 321 May 13 README.md
-rw-r--r-- 1 levo levo 1024 May 13 data.csv
Идеальная команда когда хочешь видеть вывод и сохранить его одновременно.
tee -a: append
$ command | tee -a log.txt
# Не перезаписывает log.txt, дописывает в конец.
tee для sudo-write
# [X] НЕ РАБОТАЕТ: redirect выполняется shell-ом ПЕРЕД sudo
$ sudo echo "127.0.0.1 myhost" > /etc/hosts
# Permission denied — shell пытается открыть /etc/hosts для записи под своим UID
# [x] tee решает: sudo применяется к tee, который пишет в /etc/hosts
$ echo "127.0.0.1 myhost" | sudo tee -a /etc/hosts
127.0.0.1 myhost # вывод tee (его stdout)
$ cat /etc/hosts | tail -1
127.0.0.1 myhost # запись прошла
Это классический idiom для записи в root-only файлы из обычной shell.
tee + process substitution
# Слать в файл errors.log и одновременно делать grep WARN
$ command | tee >(grep ERROR > errors.log) | grep WARN
>(...) — process substitution (про это в модуле 9). tee получает stdin, копирует в файл-аналог >(grep ERROR > errors.log) (внутри которого grep пишет в errors.log) и в stdout (откуда дальше идёт | grep WARN).
Это позволяет разветвить pipeline в несколько направлений одновременно.
# Логи в три файла одновременно
$ command | tee >(grep ERROR > errors.log) >(grep WARN > warnings.log) > all.log
Pipeline pattern: command | tee output.log | grep CRITICAL
$ ./run-etl.sh | tee /var/log/etl/full.log | grep -E '(ERROR|CRITICAL)'
Полный лог пишется в full.log, на экран попадает только подсветка ошибок. После выполнения — full.log есть для post-mortem.
Combine: head + tail для slicing
# Строки с 100-й по 200-ю
$ head -n 200 file | tail -n 101 # верхние 200, потом последние 101 из них
# или через sed:
$ sed -n '100,200p' file
Попробуй сам
- Базовое:
head -n 5 /etc/passwd tail -n 5 /etc/passwd head -c 100 /etc/passwd - Tail follow:
# В одном терминале: tail -F /tmp/test.log # В другом: echo "$(date) hello" >> /tmp/test.log echo "$(date) world" >> /tmp/test.log # Должен увидеть строки в первом терминале - Skip header:
printf "header\na\nb\nc\n" | tail -n +2 # вывод: a, b, c - tee для split:
ls /etc | tee /tmp/etc.txt | wc -l # tee копирует в /tmp/etc.txt, wc -l получает stdin # Видишь число файлов cat /tmp/etc.txt | head
macOS-различия
- head, tail, tee на macOS работают идентично GNU-версиям для базовых флагов.
- tail -F: на macOS работает через kqueue (BSD), на Linux — через inotify. Поведение для пользователя одинаковое.
- tail -n -3 (отрицательное = «все, кроме последних 3») — поддерживается обеими.
- head -c на BSD требует число без единиц (
head -c 1024), GNU поддерживает суффиксы (head -c 1K).
Главное
head -n N— первые N строк,head -c N— первые N байт.head -n -N— все, кроме последних N (отрицательное).tail -n N— последние N строк,tail -n +N— с N-й строки.tail -f— следить за файлом (FD-based).tail -F— следить по имени (handles log rotation).tee FILE— копирует stdin в файл И stdout.-aappend. Идиома... | sudo tee /etc/fileдля записи в root-файлы.tee >(cmd1) >(cmd2)— разветвление pipeline в несколько направлений (process substitution).- Для real-time filter добавь
--line-bufferedв grep, чтобы не было buffer-delay.