grep, curl и jq
Updated Jul 2026
Большая тройка для QA-инженеров
Три команды справляются с подавляющим большинством задач QA-расследований в командной строке: grep для поиска по логам и файлам, curl для выполнения HTTP-запросов и jq для парсинга JSON-ответов. Освойте эти три инструмента, и вы сможете диагностировать большинство проблем из терминала.
grep -- Поиск по логам и файлам
grep ищет шаблоны в файлах и выводит совпавшие строки. Это ваш первый инструмент при расследовании сбоев в лог-файлах.
Базовое использование
# Найти строки с ERROR в лог-файле
grep "ERROR" /var/log/app/application.log
# Поиск без учёта регистра
grep -i "null pointer" /var/log/app/application.log
# Показать 3 строки контекста вокруг каждого совпадения (до и после)
grep -C 3 "ERROR" /var/log/app/application.log
# Показать только 3 строки перед совпадением
grep -B 3 "ERROR" /var/log/app/application.log
# Показать только 3 строки после совпадения
grep -A 3 "ERROR" /var/log/app/application.log
Поиск по нескольким файлам
# Рекурсивный поиск во всех тестовых файлах
grep -r "data-testid=\"checkout" tests/
# Рекурсивный поиск с отображением имени файла
grep -rn "data-testid=\"checkout" tests/
# tests/checkout.spec.ts:15: await page.locator('[data-testid="checkout"]').click()
# Поиск только по определённым типам файлов
grep -r --include="*.ts" "waitForTimeout" tests/
# Исключить каталоги из поиска
grep -r --exclude-dir=node_modules "TODO" .
Подсчёт и фильтрация
# Подсчёт совпавших строк
grep -c "ERROR" /var/log/app/application.log
# Вывод: 47
# Подсчёт ошибок 500 в логах nginx
grep "HTTP 500" /var/log/nginx/access.log | wc -l
# Показать только совпавшую часть строки (не всю строку)
grep -o "HTTP [0-9]\{3\}" /var/log/nginx/access.log | sort | uniq -c | sort -rn
# Вывод:
# 12847 HTTP 200
# 234 HTTP 404
# 47 HTTP 500
# 12 HTTP 503
# Инвертировать совпадение: показать строки, которые НЕ совпадают
grep -v "healthcheck" /var/log/app/application.log
# Исключить шумные строки проверок здоровья из анализа логов
# Несколько шаблонов (логика ИЛИ)
grep -E "ERROR|FATAL|CRITICAL" /var/log/app/application.log
Регулярные выражения с grep
# Найти строки с временными метками в определённом диапазоне
grep -E "2024-01-15 14:3[0-9]:" /var/log/app/application.log
# Найти email-адреса
grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" users.txt
# Найти IP-адреса
grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log
curl -- Выполнение HTTP-запросов
curl отправляет HTTP-запросы из командной строки. Незаменимый инструмент для быстрого тестирования API, проверок здоровья и отладки сетевых проблем.
Базовые запросы
# GET-запрос
curl https://api.example.com/users
# Форматированный вывод JSON-ответа (через jq)
curl -s https://api.example.com/users | jq .
# POST с JSON-телом
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "Test User", "email": "test@example.com"}'
# PUT-запрос
curl -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Updated User"}'
# DELETE-запрос
curl -X DELETE https://api.example.com/users/123 \
-H "Authorization: Bearer $TOKEN"
Исследование ответов
# Только заголовки ответа (HEAD-запрос)
curl -I https://api.example.com/users
# HTTP/2 200
# content-type: application/json
# cache-control: no-cache
# Подробный вывод (отладка проблем соединения)
curl -v https://api.example.com/users
# Показывает: DNS-разрешение, TCP-соединение, TLS-рукопожатие, заголовки запроса, заголовки ответа
# Показать заголовки ответа вместе с телом
curl -i https://api.example.com/users
# Показать только HTTP-код статуса
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/users
# Вывод: 200
Измерение времени запросов
# Замер времени запроса (полезно для тестирования производительности)
curl -w "\nTime: %{time_total}s\nHTTP Code: %{http_code}\n" \
-o /dev/null -s https://api.example.com/users
# Вывод:
# Time: 0.245s
# HTTP Code: 200
# Подробная разбивка по фазам
curl -w "\nDNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nFirst byte: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-o /dev/null -s https://api.example.com/users
Практические сценарии curl
# Загрузка файла
curl -X POST https://api.example.com/upload \
-F "file=@screenshot.png" \
-H "Authorization: Bearer $TOKEN"
# Следовать перенаправлениям
curl -L https://example.com/old-url
# Сохранить ответ в файл
curl -o response.json https://api.example.com/users
# Отправить запрос с куками
curl -b "session=abc123" https://api.example.com/profile
# Установить таймаут (предотвратить зависание)
curl --max-time 30 https://slow-api.example.com/endpoint
# Повторить при сбое
curl --retry 3 --retry-delay 5 https://flaky-api.example.com/endpoint
jq -- Парсинг JSON
jq -- это консольный процессор JSON. Большинство API возвращают JSON, и jq позволяет извлекать, фильтровать и трансформировать эти данные.
Базовое использование
# Форматированный вывод JSON
curl -s https://api.example.com/users | jq .
# Извлечь конкретное поле
curl -s https://api.example.com/users/1 | jq '.name'
# Вывод: "John Doe"
# Извлечь вложенное поле
curl -s https://api.example.com/users/1 | jq '.address.city'
# Вывод: "New York"
# Извлечь из массива
curl -s https://api.example.com/users | jq '.[0].name'
# Вывод: "John Doe" (имя первого пользователя)
# Получить все имена из массива
curl -s https://api.example.com/users | jq '.[].name'
# Вывод:
# "John Doe"
# "Jane Smith"
# "Bob Wilson"
Фильтрация и выборка
# Фильтрация элементов массива
curl -s https://api.example.com/users | jq '.[] | select(.role == "admin")'
# Фильтрация по числовому сравнению
curl -s https://api.example.com/orders | jq '.[] | select(.total > 100)'
# Фильтрация по содержимому строки
curl -s https://api.example.com/users | jq '.[] | select(.email | contains("@example.com"))'
# Несколько условий
curl -s https://api.example.com/users | jq '.[] | select(.role == "admin" and .active == true)'
Трансформация данных
# Подсчёт элементов в массиве
curl -s https://api.example.com/users | jq length
# Вывод: 42
# Создать объект новой формы
curl -s https://api.example.com/users | jq '.[] | {name: .name, email: .email}'
# Извлечь конкретные поля в CSV-подобный формат
curl -s https://api.example.com/users | jq -r '.[] | [.id, .name, .email] | @csv'
# Вывод:
# 1,"John Doe","john@example.com"
# 2,"Jane Smith","jane@example.com"
# Сортировка по полю
curl -s https://api.example.com/users | jq 'sort_by(.created_at) | reverse'
# Группировка по полю
curl -s https://api.example.com/users | jq 'group_by(.role) | .[] | {role: .[0].role, count: length}'
Работа с локальными файлами
# Парсинг локального JSON-файла
jq '.dependencies' package.json
# Извлечение тестовой конфигурации
jq '.scripts | to_entries | .[] | select(.key | startswith("test"))' package.json
# Модификация JSON (полезно для тестовых данных)
jq '.baseURL = "https://staging.example.com"' config.json > config-staging.json
Комбинирование grep, curl и jq
Настоящая мощь проявляется при комбинировании этих инструментов:
# Проверить здоровье API и уведомить при ненулевом коде
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health)
[ "$STATUS" -ne 200 ] && echo "API is down! Status: $STATUS"
# Найти всех админов и посчитать их
curl -s https://api.example.com/users | jq '[.[] | select(.role == "admin")] | length'
# Искать конкретные данные в ответе API
curl -s https://api.example.com/products | jq '.[] | select(.name | test(".*phone.*"; "i"))'
# Мониторинг времени отклика эндпоинта в цикле
while true; do
TIME=$(curl -s -o /dev/null -w "%{time_total}" https://api.example.com/health)
echo "$(date): ${TIME}s"
sleep 10
done
awk и sed (краткий справочник)
Два дополнительных инструмента обработки текста, дополняющие grep:
# awk: Вычислить среднее время отклика из лога
awk '{sum += $4; count++} END {print sum/count "ms"}' response-times.log
# awk: Вывести конкретные столбцы
awk '{print $1, $4, $7}' /var/log/nginx/access.log
# sed: Заменить staging URL на production URL
sed 's/staging.example.com/prod.example.com/g' test-config.json
# sed: Удалить строки, соответствующие шаблону
sed '/healthcheck/d' application.log
# sed: Вставить текст в начало файла
sed -i '1i # This is a test configuration file' config.json
ssh и scp
Доступ к удалённым серверам необходим для QA-работы в нелокальных окружениях:
# Подключиться к удалённому серверу
ssh qa@staging-server.example.com
# Выполнить команду на удалённом сервере без интерактивной сессии
ssh qa@staging-server.example.com "ps aux | grep node"
# Скопировать результаты тестов с удалённого на локальный
scp qa@staging-server.example.com:/var/log/test-results.xml ./
# Скопировать файл с локального на удалённый
scp test-data.json qa@staging-server.example.com:/tmp/
# SSH-туннель: доступ к удалённой базе данных локально
ssh -L 5432:localhost:5432 qa@staging-server.example.com
# Теперь подключайтесь к localhost:5432 для доступа к удалённому Postgres
Практическое упражнение
- Используйте
grepдля поиска всех строк ERROR в лог-файле, затем подсчитайте количество уникальных сообщений об ошибках - Используйте
curlдля выполнения GET- и POST-запросов к публичному API (например, https://jsonplaceholder.typicode.com) - Используйте
jqдля извлечения и фильтрации данных из ответа API - Объедините все три: получите список пользователей через
curl, разберите черезjqдля поиска администраторов и пропустите черезgrepдля поиска определённого email-домена - Замерьте время API-запроса с помощью
curl -wи определите, какая фаза (DNS, connect, TLS, first byte) самая медленная - Напишите однострочник, который мониторит эндпоинт каждые 10 секунд и логирует код статуса и время отклика