Как проверить синтаксис скрипта 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!


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

это работает, потому что 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» в зависимости от ваших потребностей

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.