Как проверить синтаксис скрипта Bash без его запуска?

267

Можно ли проверить синтаксис bash-скрипта, не выполняя его?

Используя Perl, я могу бегать perl -c 'script name'. Есть ли эквивалентная команда для скриптов bash?

Том Файнер
источник

Ответы:

381
bash -n scriptname

Возможно очевидное предостережение: это проверяет синтаксис, но не проверяет, пытается ли ваш bash-скрипт выполнить команду, которой нет в вашем пути, как ech helloвместо echo hello.

Энди
источник
9
На man-странице bash в разделе «КОМАНДЫ / НАСТРОЙКИ ОБОЛОЧКИ ОБЪЕКТА» задокументирована -n, и, как указано в начале man-страницы, bash интерпретирует все доступные односимвольные опции set.
ephemient
24
чтобы добавить к (не для меня) неочевидное предостережение, он также не поймает ошибку, вызванную отсутствием пробела if ["$var" == "string" ]вместоif [ "$var" == "string" ]
Brynjar
11
@Brynjar Это потому, что это просто проверка синтаксиса. Открытая скобка - это не синтаксис, это имя функции, которую нужно запустить. type [говорит "[это встроенная оболочка". В конечном итоге он делегирует testпрограмме, но также ожидает закрывающую скобку. Таким образом if test"$var", это не то, что имел в виду автор, но синтаксически допустимо (скажем, $ var имеет значение «a», тогда мы увидим «bash: testa: команда не найдена»). Дело в том, что синтаксически нет пропущенного места.
Джошуа Чик
2
@JoshuaCheek: [в этом случае встроенный вызов вызывается только в том случае, если он $varрасширяется до пустой строки . Если $varрасширяется до непустой строки, [как сцепляется с этой строкой и интерпретируются как команда имя (не функция имя) на Bash, и, да, то есть синтаксический действительно, но, как вы заявляете, очевидно , не намерена. Если вы используете [[вместо [, даже если [[это ключевое слово оболочки (а не встроенное), вы получите тот же результат, потому что непреднамеренная конкатенация строк по-прежнему отменяет распознавание ключевого слова.
mklement0
2
@JoshuaCheek: Bash еще синтаксис проверяюще здесь: это проверка простой команды вызова синтаксис: ["$var"является синтаксический допустимым именем команды выражения; Точно так же токены ==и "$string"являются действительными аргументами команды . ( Как правило, встроенный [разбираются с командой синтаксисом, тогда [[- как оболочка ключевым слова - анализируются по- разному.) Встроенная команда оболочки [никак не делегирует на « testпрограмму» (внешняя утилита): bash, dash, ksh, zshвсе они имеют встроенные версии как [иtestи они не называют своих внешних утилитарных аналогов.
mklement0
127

Время меняет все. Вот веб-сайт, который обеспечивает онлайн-проверку синтаксиса сценария оболочки.

Я обнаружил, что это очень мощное обнаружение распространенных ошибок.

введите описание изображения здесь

О ShellCheck

ShellCheck - это инструмент статического анализа и линтинга для скриптов sh / bash. Он в основном сосредоточен на обработке типичных синтаксических ошибок начального и промежуточного уровня и ловушек, когда оболочка просто дает загадочное сообщение об ошибке или странном поведении, но также сообщает о нескольких более сложных проблемах, где угловые случаи могут привести к задержке сбоев.

Исходный код на Haskell доступен на GitHub!

dvd818
источник
5
Отличный совет; на OSX теперь вы можете также установить shellcheck.net CLI, shellcheckчерез Homebrew : brew install shellcheck.
mklement0
3
Также на debian & friends:apt-get install shellcheck
тот другой парень
Для Ubuntu trusty этот пакет должен быть установлен с trusty-backports.
Петерино
Как упоминалось выше, нужна надежная зависимость, и вы можете установить ее, как показано ниже в ubuntu 14.04: sudo apt-get -f install, затем: sudo sudo apt-get install shellcheck
zhihong
Это действительно полезно, но он использует не парсер Bash, а свой собственный. В большинстве случаев это достаточно хорошо и может идентифицировать как синтаксический анализ, так и другие проблемы, но есть по крайней мере один крайний случай (и, вероятно, другие, которые я не видел), где он не анализируется совершенно одинаково.
Даниэль Х
38

Я также включаю опцию 'u' в каждом скрипте bash, который я пишу, чтобы выполнить дополнительную проверку:

set -u 

Это сообщит об использовании неинициализированных переменных, как в следующем скрипте 'check_init.sh'

#!/bin/sh
set -u
message=hello
echo $mesage

Запуск скрипта:

$ check_init.sh

Сообщит следующее:

./check_init.sh[4]: mesage: Параметр не задан.

Очень полезно ловить опечатки

Диего Терцеро
источник
4
я всегда устанавливаю эти флаги в моих скриптах bash, если они проходят, хорошо бы перейти "set -o errexit" "set -o nounset" "set -o pipefail"
μολὼν.λαβέ
+1, set -uхотя это на самом деле не отвечает на вопрос, потому что вы должны запустить скрипт, чтобы получить сообщение об ошибке. Даже не bash -n check_init.shпоказывает, что предупреждение
rubo77
23
sh  -n   script-name 

Запустите это. Если в скрипте есть какие-либо синтаксические ошибки, он возвращает то же сообщение об ошибке. Если ошибок нет, то выходит без сообщения. Вы можете проверить сразу с помощью echo $?, который вернет 0подтверждение успешной без каких-либо ошибок.

У меня это хорошо сработало. Я работал на ОС Linux, Bash Shell.

Дживан
источник
1
Хотя это не совсем относится к проверке синтаксиса bash - использование set -x и set + x для отладки полного скрипта или его частей довольно полезно
GuruM
Спасибо за это, я не знал, не знал о -n, но я хотел, чтобы @GuruM> sh -x test.sh отображал сгенерированный вывод сценария
zzapper
1
Да. Я забыл упомянуть, что вы можете сделать следующее В командной строке: 1) bash -x test.sh # Это запускает весь скрипт в «режиме отладки» 2) set + x; bash test.sh; установить -x #set режим отладки вкл / выкл до / после запуска скрипта В скрипте: a) #! / bin / bash -x #add 'режим отладки' в верхней части скрипта b) set + x; код; установить -x #add 'режим отладки' для любого раздела скрипта
GuruM
sh -nвероятно, не будет проверять, что скрипт является действительным сценарием Bash. Это может дать ложные негативы. shкакой-то вариант оболочки Bourne, обычно не Bash. Например в Ubuntu Linux realpath -e $(command -v sh)выдает / bin / dash
jarno
4

Я на самом деле проверяю все скрипты bash в текущем каталоге на наличие синтаксических ошибок БЕЗ запуска их с помощью findинструмента:

Пример:

find . -name '*.sh' -exec bash -n {} \;

Если вы хотите использовать его для одного файла, просто отредактируйте шаблон с именем файла.

Джеральд Хьюз
источник
3

Пустая команда [двоеточие] также полезна при отладке, чтобы увидеть значение переменной

set -x
for i in {1..10}; do
    let i=i+1
    : i=$i
done
set - 
mug896
источник
он использует расширения параметров
mug896
это работает, потому что set -xпоказывает каждую строку перед ее выполнением
rubo77
1

Существует BashSupport плагин для IntelliJ IDEA , который проверяет синтаксис.

Чингиз
источник
Но это не сработает, если ваши файлы не заканчиваются .shили не имеют другого расширения, связанного со скриптами Bash, что имеет место, если вы генерируете скрипты, используя какой-либо шаблонизатор, такой как ERB (тогда они заканчиваются .erb). Пожалуйста, проголосуйте за youtrack.jetbrains.com/issue/IDEA-79574, если хотите, чтобы это было исправлено!
Грег Дубицки
1

Если вам требуется в переменной допустимость всех файлов в каталоге (git pre-commit hook, build lint script), вы можете получить вывод stderr команд "sh -n" или "bash -n" (см. Другие ответы) в переменной, и иметь «если / еще» на основе этого

bashErrLines=$(find bin/ -type f -name '*.sh' -exec sh -n {} \;  2>&1 > /dev/null)
  if [ "$bashErrLines" != "" ]; then 
   # at least one sh file in the bin dir has a syntax error
   echo $bashErrLines; 
   exit; 
  fi

Замените «sh» на «bash» в зависимости от ваших потребностей

Элвис Чиотти
источник