Learning Platform
Глоссарий Troubleshooting
Урок 08.04 · 15 мин
Начальный
wcLine countByte countUTF-8Text processing

Что считает wc

wc (word count) — простая утилита для подсчёта строк, слов, байтов или символов в файле или stdin. Один из старейших UNIX-инструментов (UNIX V1, 1971).

Базовый запуск без флагов:

$ wc /etc/passwd
   42  120 2389 /etc/passwd

Три числа: lines, words, bytes. Для DE интереснее по одному:

Флаги wc

Каждый флаг отвечает за одну метрику.

-lстроки (line count)Количество newline-символов в input. Если файл не заканчивается на \\n — последняя строка НЕ считается. Это часто удивляет: 'echo -n hello | wc -l' = 0.
-wслова (word count)Слова разделены whitespace (пробелы, табы, newline). 'hello world' = 2 слова. 'hello world' (несколько пробелов) тоже 2 слова.
-cБАЙТЫ (не символы!)Количество байт в input. Для ASCII = количество символов. Для UTF-8 русский 'Привет' = 12 байт (по 2 байта на букву). НЕ путать с -m.
-mсимволы (chars, UTF-8 aware)Количество символов с учётом текущего locale. Для UTF-8 'Привет' = 6 символов. Для ASCII = то же, что -c.
-Lдлина самой длинной строкиПолезно для проверки 'все ли строки в файле короче 80 символов'.

Самый частый: wc -l

$ wc -l data.csv
1247 data.csv

$ wc -l < data.csv
1247
# < (input redirection) убирает имя файла из вывода — удобно для скриптов

$ ls /var/log/ | wc -l
38
# Сколько файлов в /var/log/

Gotcha: trailing newline

$ printf "hello" | wc -l    # без \n в конце
0

$ printf "hello\n" | wc -l   # с \n в конце
1

wc считает newline-символы, не «строки в человеческом понимании». Файл без trailing \n даст один «недосчитанный» лайн. На POSIX-системах это часть стандарта: каждая строка ДОЛЖНА заканчиваться на \n. Большинство утилит ведёт себя именно так.

Это аккуратно: если у тебя файл с N строками и wc -l показывает N-1 — проверь, есть ли \n в конце:

$ tail -c 1 file.csv | xxd
00000000: 0a                                       .

# Если последний байт 0x0a — это \n, всё хорошо
# Если что-то другое — последняя строка без newline

CSV: сколько rows

$ wc -l data.csv
1248 data.csv
# 1248 строк всего, но одна — заголовок
# rows = 1248 - 1 = 1247

# Без header:
$ tail -n +2 data.csv | wc -l
1247

tail -n +2 начинает с 2-й строки (skip header). Это идиома wc -l rows для CSV с header.

DE-кейсы

1. Размер набора данных

$ wc -l /data/orders/*.csv
   1247 orders_2026_05_10.csv
   1389 orders_2026_05_11.csv
   1450 orders_2026_05_12.csv
   4086 total

С несколькими файлами wc добавляет строку total — полезно для quick sanity check.

2. Самые «толстые» файлы по строкам

$ find . -name '*.py' -exec wc -l {} + | sort -n | tail -10
   234 dags/load_dim_users.py
   289 dags/process_events.py
   312 dags/sync_orders.py
   ...
   1247 utils/legacy_helpers.py

find ... -exec wc -l {} + — батчинг (плюс), пакет файлов одним вызовом wc. Гораздо быстрее -exec ... \;. Сортировка по строкам подсвечивает самые большие файлы — кандидаты на refactor.

3. Подсчёт уникальных значений

$ cut -d ',' -f 4 orders.csv | sort -u | wc -l
12
# 12 уникальных стран в orders

4. Топ N с подсчётом

# Все ERROR в логе за сегодня (сегодняшняя дата в начале строки)
$ grep -c "^$(date +%Y-%m-%d).*ERROR" app.log
73

grep -c быстрее grep ... | wc -l: grep не строит вывод и не открывает второй pipe.

5. Размер файла в байтах

$ wc -c data.csv
123456 data.csv

# Или через stat для большей точности:
$ stat -c '%s' data.csv
123456

Для размера лучше stat или ls -l: они читают метаданные inode, не file content. wc -c должен прочитать весь файл (на современном wc оптимизация — sized files через lseek к концу, но на streams не работает).

Bytes vs Chars: критично для UTF-8

$ echo -n "Привет" > greeting.txt
$ wc -c greeting.txt
12 greeting.txt           # 12 байт
$ wc -m greeting.txt
6 greeting.txt            # 6 символов

$ echo -n "hello" > hello.txt
$ wc -c hello.txt
5 hello.txt               # 5 байт
$ wc -m hello.txt
5 hello.txt               # 5 символов (ASCII = bytes == chars)

UTF-8 кириллица — 2 байта на букву. Эмодзи — 4 байта (некоторые до 8 в surrogate pairs). Для длинных файлов это важная разница.

В DE-задачах это критично:

  • Limits в БД часто в байтах (VARCHAR(255) в MySQL latin1 = 255 байт, в utf8mb4 — 255 символов = до 1020 байт)
  • Limits API — иногда в символах (Twitter character limit), иногда в байтах
  • HTTP Content-Length — всегда байты

wc через stdin

wc принимает stdin когда нет файлов в аргументах:

$ ls /var/log | grep '.log$' | wc -l
12

$ ps -ef | grep python | wc -l
4

Это classic Linux idiom: «как много чего-то». wc -l — это «COUNT(*) в bash».

Когда wc недостаточно

wc примитивен. Для сложного counting:

  • uniq -c — count по группам
  • awk — programmable count с условиями
  • grep -c — count строк со совпадением (быстрее wc -l после grep)

Например:

# Сколько уникальных users заходило в системе?
$ awk -F: '{print $1}' /etc/passwd | wc -l    # все users
$ awk -F: '$3 >= 1000 {print $1}' /etc/passwd | wc -l   # только regular

awk здесь добавляет фильтр (UID >= 1000), который wc сам сделать не может.

Попробуй сам

  1. Считай строки в /etc/passwd:
    wc -l /etc/passwd
  2. Сколько Python-файлов в проекте:
    find . -name '*.py' 2>/dev/null | wc -l
  3. Размер самого длинного слова в /usr/share/dict/words (если есть):
    wc -L /usr/share/dict/words 2>/dev/null
  4. Сравни bytes и chars для UTF-8:
    echo -n "日本語" | wc -c       # 9 байт
    echo -n "日本語" | wc -m       # 3 символа
  5. Топ-5 самых больших файлов в /etc:
    wc -l /etc/* 2>/dev/null | sort -n | tail -6 | head -5

macOS-различия

  • wc на macOS идентичен GNU wc для базовых флагов.
  • -L (longest line length) поддерживается на BSD wc.
  • Поведение wc -m зависит от LANG / LC_ALL: если выставлен UTF-8, считаются символы; если C/POSIX — считаются байты (то же, что -c).
Проверка знанийKnowledge check
Файл cyrillic.txt содержит ровно один русский слов 'тестирование' без \n в конце. Что вернёт 'wc -c cyrillic.txt' и 'wc -m cyrillic.txt'?
ОтветAnswer
wc -c вернёт 24 (12 символов кириллицы × 2 байта = 24 байта в UTF-8). wc -m вернёт 12 (количество символов). Это иллюстрирует ключевую разницу: -c считает БАЙТЫ независимо от encoding, -m считает SYMBOLS с учётом текущего locale. UTF-8 для кириллицы использует 2 байта на букву, для японского/китайского — 3 байта, для emoji — 4 байта. Если locale установлен в C/POSIX (а не en_US.UTF-8), wc -m может вернуть 24 как -c, потому что не знает про multibyte. Это важно знать когда работаешь с VARCHAR-limits в БД (MySQL utf8mb4 — символы; MySQL latin1 — байты), с HTTP Content-Length (всегда байты), с file system sizes (всегда байты). wc -l для этого файла вернёт 0, потому что нет \n в конце.

Главное

  • wc -l — строки (newline count, требует trailing \n).
  • wc -w — слова (whitespace-separated).
  • wc -cБАЙТЫ, не символы.
  • wc -m — символы (UTF-8 aware с правильным locale).
  • wc -L — длина самой длинной строки.
  • Для размера лучше stat или ls -l (читает metadata, не content).
  • Без trailing \n в файле последняя «строка» не засчитается в -l.
  • Для CSV с header: tail -n +2 file.csv | wc -l или ($(wc -l < file.csv) - 1).
  • grep -c PATTERN file быстрее grep PATTERN file | wc -l.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Команда 'printf "hello" | wc -l' возвращает 0. Это баг или ожидаемое поведение?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5