← Весь справочник

shellcheck

Статический анализатор shell-скриптов — находит ошибки с кавычками, условиями и переносимостью

shellcheck читает скрипт, не запуская его, и указывает на типичные ошибки: переменные без кавычек, cd без проверки, цикл по выводу ls, bash-конструкции в #!/bin/sh. У каждого предупреждения есть код SCxxxx — по нему на shellcheck.net/wiki есть подробное объяснение с примером исправления.

Синтаксис

shellcheck [опции] скрипт…

Диалект берётся из shebang (#!/bin/bash, #!/bin/sh) или из опции -s. Код возврата: 0 — замечаний нет, 1 — есть замечания, 2 — файл не прочитан, 3 и 4 — ошибка в опциях.

Опции

ОпцияЧто делает
-s bash / -s sh / -s dash / -s kshдиалект, если в файле нет shebang
-S error / warning / info / styleпоказывать только замечания этого уровня и серьёзнее
-e SC2086,SC2034исключить указанные коды
-i SC2086показывать только указанные коды
-o all / -o имявключить необязательные проверки (по умолчанию выключены)
--list-optionalсписок необязательных проверок с примерами
-xзаходить в файлы, подключённые через source / .
-P путьгде искать подключаемые файлы (SCRIPTDIR — каталог скрипта)
-aпоказывать замечания и по подключённым файлам
-f ttyформат по умолчанию: строка кода, стрелка, объяснение, «Did you mean»
-f gccодна строка на замечание: файл:строка:столбец: уровень: текст [SCxxxx]
-f diffисправления в виде патча (shellcheck -f diff s.sh | patch -p1)
-f json1 / -f checkstyleмашиночитаемый вывод для CI
-f quietничего не печатать, только код возврата
--color=neverбез цветов (у -C значение пишется слитно: -Cnever)
-W 0не печатать ссылки на wiki в конце
--norcне читать .shellcheckrc
- вместо файлачитать скрипт со stdin

Уровни

УровеньЧто обычно означает
errorпочти наверняка ошибка: синтаксис, цикл по $(ls), [[ в sh
warningвероятный баг: cd без проверки, переменная не задана или не используется
infoстоит исправить: кавычки, read без -r
styleстиль: $(…) вместо обратных кавычек, [[ ]] вместо [ ]

Директивы в скрипте

КомментарийЧто делает
# shellcheck disable=SC2086отключить код для следующей команды (или блока { … }, функции, цикла)
то же сразу после shebang, до первой командыотключить для всего файла
# shellcheck disable=SC2086,SC2154несколько кодов через запятую
# shellcheck source=lib.shкакой файл на самом деле подключает source "$dir/lib.sh"
# shellcheck source=/dev/nullне пытаться читать подключаемый файл
# shellcheck shell=bashзадать диалект внутри файла без shebang

Файл .shellcheckrc в каталоге проекта или в домашнем каталоге задаёт те же директивы для всех скриптов: disable=SC2086, enable=all, shell=bash.

Частые коды

КодСуть
SC2086переменная без кавычек будет разбита на слова и раскрыта как шаблон
SC2164cd без || exit: если каталога нет, команды выполнятся не там
SC2045for f in $(ls …) ломается на пробелах — используй glob
SC2154переменная используется, но нигде не присвоена
SC2034переменная присвоена, но не используется
SC2162read без -r портит обратные слэши
SC2155local x=$(cmd) прячет код возврата cmd
SC2148нет shebang — непонятно, какой это диалект
SC1091подключаемый файл не прочитан (нужен -x)
SC3010 и другие SC3xxxbash-конструкция в POSIX sh

Примеры

# проверить скрипт
shellcheck deploy.sh

# компактный вывод — удобно для grep и редакторов
shellcheck -f gcc deploy.sh

# только ошибки и предупреждения, без info и style
shellcheck -S warning deploy.sh

# скрипт без shebang
shellcheck -s bash script

# проверить все .sh в проекте
find . -name '*.sh' -exec shellcheck {} +

# посмотреть предлагаемые исправления патчем
shellcheck -f diff deploy.sh

# в CI: упасть, если есть хоть одно замечание
shellcheck -f quiet *.sh || exit 1

# проверить кусок кода со stdin
echo 'echo $1' | shellcheck -s bash -

Подводные камни

  • shellcheck не запускает скрипт. Он не знает, существуют ли файлы и команды, и не найдёт логических ошибок. Чистый вывод не значит «скрипт работает».
  • Без shebang почти все проверки диалекта отключены, а первым замечанием будет SC2148. Ставь #!/bin/bash или передавай -s.
  • #!/bin/sh — это не bash. [[ ]], массивы, &> дадут SC3xxx. Это правда: в Ubuntu sh — это dash, и такой скрипт сломается.
  • Директива действует на следующую команду, а не на строку. Комментарий в конце строки (echo $x # shellcheck disable=…) — ошибка разбора SC1126. А директива сразу после shebang, перед первой командой, отключает проверку во всём файле.
  • disable глушит симптом. Прежде чем отключать SC2086, убедись, что разбиение на слова действительно нужно.
  • Подключаемые файлы по умолчанию не читаются: переменные из них покажутся неприсвоенными (SC2154). Добавь -x.

См. также

variables · conditions-loops · exit-codes · find