Проверка синтаксиса Bash-скриптов: bash -n и ShellCheck
Используйте bash -n для быстрой синтаксической проверки скрипта и ShellCheck для глубокого анализа, подсказок и предупреждений. Добавьте ShellCheck в редактор и CI, чтобы ловить ошибки до запуска и снизить риск неопределённого поведения.
Быстрые ссылки
Те надоедливые ошибки
Тестирование сложно
Использование bash для проверки синтаксиса
Утилита ShellCheck
Установка ShellCheck
Использование ShellCheck
ShellCheck — ваш друг

Введение
Ошибки и опечатки в Bash-скриптах могут привести к серьёзным последствиям при их выполнении. В этой статье показаны несколько способов проверки синтаксиса и качества shell-скриптов до запуска: встроенная проверка Bash с опцией -n и статический анализатор ShellCheck. Мы объясним, как и когда использовать каждый инструмент, какие ограничения у них есть, как интегрировать ShellCheck в рабочий процесс и дадим практические чек-листы и рекомендации.
Те надоедливые ошибки
Писать код трудно. Писать безошибочный код — ещё сложнее. Чем больше строк кода, тем выше вероятность ошибок. Язык программирования влияет на сложность: чем ближе язык к машине, тем больше забот ложится на автора. Bash — язык со своими подводными камнями: внешние утилиты, особенности подстановки, кавычек и арифметики — всё это даёт место для ошибок.
Скомпилированные языки дают частичную защиту: компилятор обнаруживает синтаксические ошибки и многие классы неграмотно написанного кода. Скриптовые языки, и особенно shell, часто не дают таких гарантий: многие ошибки проявляются только во время выполнения и зависят от окружения и входных данных.
Некоторые ошибки синтаксические — их легко отловить. Другие — логические: программа делает ровно то, что вы ей сделали написать, но не то, чего вы ожидали. Такие ошибки труднее обнаруживать автоматами и требуют тестирования и рецензирования.
Тестирование трудно
Тщательное тестирование любого кода занимает время. Несколько запусков недостаточно: нужно покрыть все ветви выполнения, проверить корректную обработку ошибок и невалидного ввода. Для скриптов это особенно важно, так как у них часто нет модульных тестов и контрактов.
Для многих языков есть юнит-тесты и CI, а для shell-скриптов можно и нужно применять статический анализ и линтеры, которые помогут ловить паттерны ошибок раньше, чем они попадут в продакшен.
Использование Bash для проверки синтаксиса
Bash имеет встроенную опцию -n (noexec). Она заставляет интерпретатор прочитать скрипт и проверить синтаксис, но не выполнять его. Это безопасный способ обнаружить синтаксические ошибки, не запуская потенциально опасные команды.
Ниже — пример скрипта, который мы будем проверять. Он несложный: несколько условных операторов if. Скрипт запрашивает номер месяца (1..12) и определяет сезон. Скрипт уязвим, если пользователь не вводит данные или вводит нечисловой символ.
#! /bin/bashread -p “Enter a month (1 to 12): “ month
if [ -z “$month” ]
then
echo “You must enter a number representing a month.”
exit 1
fi
if (( “$month” < 1 || “$month” > 12)); then
echo “The month must be a number between 1 and 12.”
exit 0
fi
if (( “$month” >= 3 && “$month” < 6)); then
echo “That’s a Spring month.”
exit 0
fi
if (( “$month” >= 6 && “$month” < 9)); then
echo “That’s a Summer month.”
exit 0
fi
if (( “$month” >= 9 && “$month” < 12)); then
echo “That’s an Autumn month.”
exit 0
fi
echo “That’s a Winter month.”
exit 0
Разберём ключевые шаги и объясним, что делает каждый фрагмент, но сначала — как запустить проверку синтаксиса.
### Как работает bash -n
Команда
bash -n ./seasons.sh
заставляет Bash прочитать скрипт и проверить грамматику и структуры управления. Если синтаксических ошибок нет, Bash тихо завершится без сообщений — «no news is good news». Если есть синтаксические ошибки, Bash выведет сообщение и номер строки.
Важно понимать пределы этой проверки:
- Она проверяет синтаксис встроенных конструкций Bash (if, for, while, функции, арифметика и т.п.).
- Bash не выполняет внешние утилиты и не проверяет, корректно ли вы используете команды вида [ или test как внешнюю программу. Поэтому ошибки, связанные с неправильным использованием внешних утилит или опечатками в их вызовах, могут не быть замечены.
- Логические ошибки и неправильные предположения о вводе не будут найдены.
## Когда bash -n не поможет (контрпримеры)
Рассмотрим несколько распространённых случаев, когда -n молчит, а при запуске скрипт ломается:
1) Ошибка в вызове внешней программы: `[` — это часто отдельная программа `/usr/bin/[`. Если вы случайно удалите открывающую квадратную скобку или используете неверный синтаксис, bash -n может не заметить эту проблему, так как она обнаруживается уже при запуске внешней команды.
2) Ошибки, зависящие от ввода: некоторые ветви кода исполняются только при конкретных вводных данных. При проверке -n Bash не выполняет код, поэтому ошибки, которые проявляются на конкретном пути выполнения, будут пропущены.
3) Неправильные права доступа, пути, переменные окружения: bash -n не учитывает окружение исполнения и права файлов; эти факторы влияют только при реальном запуске.
Пример саботажа: убрали `then` в одной из веток — bash -n может указать на синтаксическую ошибку, но если ошибка находится в ветке, которая никогда не проверяется при первом запуске без ввода, то вы можете долго не заметить проблему при реальном использовании.
## Утилита ShellCheck
ShellCheck — это статический анализатор (линтер) для shell-скриптов. Он обнаруживает ошибки, потенциальные уязвимости, шаблонные ошибки использования кавычек, подстановок, арифметики и многое другое. В отличие от bash -n, ShellCheck анализирует код более глубоко, понимает контексты использования команд и даёт рекомендуемые правки и ссылки на документацию.
Примеры того, что ShellCheck находит:
- Проблемы с кавычками и возможные разбиения слов (SC2086 и подобные).
- Небезопасное использование команд и подстановок.
- Использование устаревших или небезопасных конструкций.
- Потенциальные логические ошибки и опасности (например, чтение ввода без флага -r).
ShellCheck даёт советы и ссылки; не всё в его выводе — критично, но всё заслуживает внимания.

## Пример: где bash -n молчит, а ShellCheck указывает на проблему
Если мы удалим открывающую скобку из условия:
if -z “$month” ] # opening bracket “[“ removed
then
echo “You must enter a number representing a month.”
exit 1
fi
Bash -n может не предупредить об этом, потому что выражение с `[` — это вызов внешней утилиты, и синтаксическая проверка не улавливает все виды неправильного её использования. ShellCheck же укажет на некорректное условие и даст рекомендации.

## Установка ShellCheck
Установить ShellCheck можно через пакетный менеджер вашей системы. Примеры:
Ubuntu / Debian:
sudo apt install shellcheck
Fedora:
sudo dnf install ShellCheck
Manjaro / Arch-based:
sudo pacman -S shellcheck
Если необходима самая свежая версия или сборка для другой платформы, можно установить через snap, Homebrew (macOS/Linux) или собрать из исходников. Документация проекта в репозитории содержит инструкции для всех распространённых платформ.
## Использование ShellCheck
Запуск прост:
shellcheck seasons.sh
Вы получите список диагностических сообщений с кодами (например, SC2086) и кратким описанием проблемы. Часто ShellCheck также даёт пример исправления и ссылку на подробную страницу с объяснением.
### Пример вывода и интерпретация
Типичный вывод ShellCheck может выглядеть так (упрощённо):
- SC2148: Не указан интерпретатор в начале файла (shebang).
- SC2086: Возможное разбиение слова при использовании переменной без кавычек.
- SC2143: Использование внешней программы вместо встроенной проверки.
- SC2002: Использование cat в ситуациях, где можно обойтись без него.
Важно различать ошибки и предупреждения. Ошибки требуют немедленного исправления; предупреждения — это советы по надёжности и надёжной практике.

## Практические рекомендации и чек-лист
Ниже — набор практических шагов и критериев, которые стоит включить в процесс разработки shell-скриптов.
Чек-лист перед коммитом:
- Запустите bash -n на скрипте.
- Запустите shellcheck и исправьте критические сообщения.
- Оцените и исправьте предупреждения, которые могут привести к неправильной обработке ввода (например, отсутствие -r у read).
- Добавьте unit-тесты или сценарии интеграционного тестирования для ключевых ветвей (например, обработка пустого ввода, нечислового ввода, крайних значений).
- Запустите скрипт в изолированной среде (контейнер или VM) с различными переменными окружения.
- Добавьте проверки на возвратные коды внешних команд и обработку ошибок.
Рольовые рекомендации:
- Разработчик: использовать ShellCheck локально, фиксировать предупреждения и документировать допущения о вводе и окружении.
- Reviewer: проверять, чтобы кавычки и проверки ошибок были везде, где требуется; убедиться, что скрипт безопасно обрабатывает ввод.
- Оператор/DevOps: интегрировать ShellCheck в CI, требовать зелёного статуса линтера перед деплоем.
## Мини-методология для исправления ошибок
1. Запустите bash -n, исправьте синтаксические ошибки.
2. Запустите shellcheck, исправьте ошибки уровня error.
3. Рассмотрите предупреждения; при сомнениях — исправьте и документируйте причину.
4. Добавьте тесты и прогоните сценарии с разными входными данными.
5. Интегрируйте линтер в CI и pre-commit hook.
## Примеры распространённых предупреждений ShellCheck и как их исправлять
- SC2086 (word splitting): всегда кавычьте переменные, когда ожидаете одну строку: use "${var}" вместо ${var}.
- SC2164 (check cd): после cd проверяйте код возврата или используйте `cd dir || exit 1`.
- SC2006/SC2034 (невостребованные переменные/команды): убирайте мёртвый код или документируйте намерение.
- Read without -r: рекомендуется `read -r var` чтобы не интерпретировать обратные слэши как escape-последовательности.
## Интеграция ShellCheck в рабочие процессы
1) Редакторы: многие плагины для VS Code, Vim, Emacs поддерживают ShellCheck и показывают предупреждения прямо при редактировании.
2) Pre-commit: добавьте shellcheck в цепочку pre-commit, чтобы не позволять коммитить плохой код.
3) CI/CD: добавьте этап линтинга в pipeline — если ShellCheck находит ошибки уровня error, сборка должна падать.
4) Обучение команды: раз в квартал проводите внутренние ревью common mistakes и демонстрации выводов ShellCheck.
Пример простой интеграции в GitHub Actions:
name: Shell Lint
on: [push, pull_request]
jobs: shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install shellcheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: Run ShellCheck
run: |
find . -type f -name "*.sh" -not -path "./.git/*" -print0 | xargs -0 shellcheck
## Шаблоны и сниппеты
Примеры полезных сниппетов и заглушек, которые можно использовать в шаблонах скриптов:
Пример безопасного чтения ввода и проверки числового значения:
read -r -p “Enter a month (1 to 12): “ month if [ -z “$month” ]; then echo “You must enter a number representing a month.” >&2 exit 1 fi if ! [[ “$month” =~ ^[0-9]+$ ]]; then echo “The month must be a number between 1 and 12.” >&2 exit 1 fi
Этот фрагмент проверяет пустой ввод, затем использует регулярное сравнение для проверки, является ли ввод числом, прежде чем делать арифметические сравнения.
## Критерии приёмки
Перед слиянием ветки с изменением shell-скриптов, убедитесь, что выполняются следующие критерии:
- Скрипт проходит bash -n без ошибок.
- ShellCheck не возвращает ошибок уровня error.
- Критические предупреждения исправлены или задокументированы.
- Добавлены тесты/инструкции по ручному тестированию ключевых путей.
- Скрипт выполняется в изолированной среде и корректно обрабатывает невалидный ввод.
## Decision flowchart (Mermaid)
flowchart TD A[Есть скрипт?] –> B{Нужно только синтаксически проверить} B – Да –> C[bash -n] C –> D{Ошибки?} D – Да –> E[Исправить синтаксис] D – Нет –> F[Запустить ShellCheck] B – Нет –> F F –> G{ShellCheck вернул ошибки} G – Да –> E G – Нет –> H[Добавить в pre-commit и CI] E –> C
## Политика безопасности и приватность
- ShellCheck анализирует локальные файлы; при использовании онлайн-сервисов или веб-интерфейса не загружайте секреты.
- В CI-пайплайне избегайте вывода секретных значений в логах; используйте masked secrets.
## Совместимость и миграция
- ShellCheck покрывает POSIX shell и различные расширения Bash. Обратите внимание на различия между dash и bash: скрипт, написанный для Bash, может не работать в sh/dash.
- Для переносимости используйте POSIX-совместимые конструкции, если скрипт должен работать в /bin/sh.
## Рольовые чек-листы
Разработчик:
- Запустил bash -n и shellcheck.
- Закрыл критические сообщения.
- Добавил тестовый сценарий на крайние случаи.
Рецензент:
- Проверил кавычки и обработки ошибок.
- Убедился, что нет ненужных вызовов внешних программ.
- Проверил документацию и допустимые входные значения.
Оператор:
- Убедился, что скрипт запускается в target-окружении.
- Добавил мониторинг и джоб для периодической проверки скриптов.
## Факт-бокс
- bash -n: синтаксическая проверка, не выполняет команд.
- ShellCheck: статический анализатор, даёт советы и ссылки.
- Интеграция в CI и pre-commit повышает качество кода.
## Короткое объявление (100–200 слов)
ShellCheck и встроенная проверка bash -n значительно упрощают создание надёжных Bash-скриптов. Bash -n быстро находит синтаксические ошибки без запуска кода; ShellCheck идёт дальше, указывая на потенциальные уязвимости, ошибки кавычек и плохие практики. Добавьте ShellCheck в редактор, pre-commit hook и CI, чтобы находить проблемы раньше и снижать риск запуска некорректных скриптов в продакшене. Этот простой набор инструментов и практик — быстрый путь к более предсказуемым и безопасным shell-скриптам.
## Сводка
- Используйте bash -n для быстрой проверки синтаксиса.
- Используйте ShellCheck для детального анализа и советов.
- Интегрируйте ShellCheck в редактор и CI.
- Следуйте чек-листам и критериям приёмки, чтобы минимизировать риски.
### Словарь (в 1 строке)
- Linтер: инструмент статического анализа кода, который указывает на потенциальные ошибки и нарушения стиля.

Похожие материалы
Добавление линзовых бликов в Photoshop
Как обновить Discord на всех устройствах
Оптимизация SSD: AHCI, TRIM и прошивки
Wide Spectrum в FaceTime на Mac — как включить
Основы Git и GitHub: создать репозиторий