Jak sprawdzić składnię skryptu Bash bez uruchamiania go?

Odpowiedzi:

380
bash -n scriptname

Być może oczywiste zastrzeżenie: sprawdza poprawność składni, ale nie sprawdza, czy skrypt bash próbuje wykonać polecenie, które nie jest na twojej ścieżce, jak ech hellozamiast echo hello.

andy
źródło
9
Na stronie podręcznika bash, w sekcji „KOMENDY / KOMPLETY BUDOWLANYCH SHELL”, -n jest udokumentowane, a na początku strony podręcznika bash interpretuje wszystkie opcje setjednoznakowe.
ephemient
24
dodać do (dla mnie) nie oczywistym zastrzeżeniem, że również nie złapie błędu spowodowanego przez brak miejsca if ["$var" == "string" ], zamiastif [ "$var" == "string" ]
Brynjar
11
@Brynjar To dlatego, że to tylko sprawdzanie składni. Otwarty nawias nie jest składnią, to nazwa funkcji do uruchomienia. type [mówi „[jest wbudowaną powłoką”. Ostatecznie deleguje się do testprogramu, ale oczekuje również zamknięcia. Więc to jest if test"$var", co nie jest tym, co miał na myśli autor, ale jest poprawne składniowo (powiedzmy, że $ var ma wartość „a”, wtedy zobaczymy „bash: testa: komenda nie znaleziona”). Chodzi o to, że składniowo nie brakuje miejsca.
Joshua Cheek
2
@JoshuaCheek: Wbudowany [jest wywoływany tylko w tym przypadku, jeśli $varzdarzy się rozwinąć do pustego ciągu . Jeśli $varrozwija się do niepustego łańcucha, [jest łączony z tym łańcuchem i interpretowany przez Bash jako nazwa polecenia (nie nazwa funkcji ), i tak, jest poprawny pod względem składniowym , ale, jak sam twierdzisz, oczywiście nie jest to intencją. Jeśli użyjesz [[zamiast tego [, mimo że [[jest słowem kluczowym powłoki (a nie wbudowanym), otrzymasz ten sam wynik, ponieważ niezamierzone połączenie ciągów znaków nadal zastępuje rozpoznawanie słowa kluczowego.
mklement0
2
@JoshuaCheek: Bash nadal sprawdza składnię - zaznacza tutaj: sprawdza składnię wywołania prostych poleceń : ["$var"jest składniowo poprawnym wyrażeniem nazwa-polecenia ; podobnie, tokeny ==i "$string"są poprawnymi argumentami polecenia . (Ogólnie, wbudowane [jest analizowana z poleceń składni, podczas gdy [[- w powłoce hasła - jest analizowana w inny sposób). Określenie wbudowane powłoki [jest nie przekazywać do „ testprogramu” (użyteczności zewnętrzna): bash, dash, ksh, zshmają wbudowany wersje zarówno [itesti nie nazywają swoich odpowiedników narzędziami zewnętrznymi.
mklement0
127

Czas zmienia wszystko. Oto strona internetowa, która zapewnia sprawdzanie składni online skryptu powłoki.

Odkryłem, że jest to bardzo potężne narzędzie do wykrywania typowych błędów.

wprowadź opis zdjęcia tutaj

Informacje o ShellCheck

ShellCheck to narzędzie do analizy statycznej i usuwania kłaczków dla skryptów sh / bash. Koncentruje się głównie na obsłudze typowych błędów składniowych i pułapek dla początkujących i średniozaawansowanych, w których powłoka po prostu wyświetla tajemniczy komunikat o błędzie lub dziwne zachowanie, ale raportuje także o kilku bardziej zaawansowanych problemach, w których przypadki narożne mogą powodować opóźnione awarie.

Kod źródłowy Haskell jest dostępny na GitHub!

dvd818
źródło
5
Świetna wskazówka; na OSX można teraz również zainstalować shellcheck.net CLI, shellcheckpoprzez Homebrew : brew install shellcheck.
mklement0
3
Także na debianie i przyjaciołach:apt-get install shellcheck
ten drugi facet
W przypadku zaufanego systemu Ubuntu pakiet ten należy zainstalować z trusty-backports.
Peterino,
Jak wspomniano powyżej, potrzebna jest niezawodna zależność i można ją zainstalować jak poniżej w Ubuntu 14.04: sudo apt-get -f install, a następnie: sudo sudo apt-get install shellcheck
zhihong
Jest to bardzo przydatne, ale nie używa parsera Basha, ale jego własny. W większości przypadków jest to wystarczająco dobre i może identyfikować zarówno parsowanie, jak i inne problemy, ale istnieje co najmniej jeden przypadek krawędzi (i prawdopodobnie inne, których nie widziałem), w którym nie analizuje się w ten sam sposób.
Daniel H
38

Włączam również opcję „u” w każdym skrypcie bash, który piszę, aby wykonać dodatkowe sprawdzenie:

set -u 

Spowoduje to zgłoszenie użycia niezainicjowanych zmiennych, jak w poniższym skrypcie „check_init.sh”

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

Uruchamianie skryptu:

$ check_init.sh

Zgłasza następujące:

./check_init.sh[4]: mesage: Parametr nie został ustawiony.

Bardzo przydatne do łapania literówek

Diego Tercero
źródło
4
ustawiam te flagi zawsze w moich skryptach bash, jeśli mi się to uda, dobrze jest przejść „set -o errexit” „set -o rzeczownik” „set -o pipefail”
μολὼν.λαβέ
+1, set -uchociaż tak naprawdę nie odpowiada na pytanie, ponieważ musisz uruchomić skrypt, aby otrzymać komunikat o błędzie. Nawet nie bash -n check_init.shpokazuje tego ostrzeżenia
rubo77
23
sh  -n   script-name 

Uruchom to. Jeśli skrypt zawiera błędy składniowe, zwraca ten sam komunikat o błędzie. Jeśli nie ma żadnych błędów, wychodzi bez podania żadnej wiadomości. Możesz natychmiast sprawdzić za pomocą echo $?, który zwróci 0potwierdzenie bez powodzenia.

To działało dla mnie dobrze. Pracowałem na Linux OS, Bash Shell.

Jeevan
źródło
1
Chociaż nie jest to dokładnie związane ze sprawdzaniem składni bash - użycie zestawu -x i set + x do debugowania pełnego skryptu lub jego części jest całkiem przydatne
GuruM
Dzięki, że nie wiedziałem, że nie wiedziałem o -n, ale chciałem @GuruM> sh -x test.sh, ponieważ wyświetla on wygenerowane wyjście skryptu
zzapper
1
Tak. Zapomniałem wspomnieć, że możesz wykonać następujące czynności W wierszu poleceń: 1) bash -x test.sh # uruchamia cały skrypt w „trybie debugowania” 2) ustaw + x; bash test.sh; ustaw -x # ustaw tryb debugowania wł. / wył. przed / po uruchomieniu skryptu W skrypcie: a) #! / bin / bash -x #add „tryb debugowania” u góry skryptu b) ustaw + x; kod; ustaw -x #add „tryb debugowania” dla dowolnej sekcji skryptu
GuruM
sh -nprawdopodobnie nie sprawdzi, czy skrypt jest prawidłowym skryptem Bash. Może dawać fałszywe negatywy. shto wariant powłoki Bourne'a, który zwykle nie jest Bash. Na przykład w Ubuntu Linux realpath -e $(command -v sh)daje / bin / dash
jarno
4

Właściwie sprawdzam wszystkie skrypty bash w bieżącym katalogu pod kątem błędów składniowych BEZ uruchamiania ich za pomocą findnarzędzia:

Przykład:

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

Jeśli chcesz go użyć do pojedynczego pliku, po prostu edytuj symbol wieloznaczny z nazwą pliku.

Gerald Hughes
źródło
3

Komenda null [dwukropek] jest również przydatna podczas debugowania, aby zobaczyć wartość zmiennej

set -x
for i in {1..10}; do
    let i=i+1
    : i=$i
done
set - 
mug896
źródło
używa rozszerzeń parametrów
mug896
to działa, ponieważ set -xpokazuje każdą linię przed jej wykonaniem
rubo77
1

Istnieje wtyczka BashSupport dla IntelliJ IDEA, która sprawdza składnię.

Cengiz
źródło
Ale to nie zadziała, jeśli twoje pliki nie kończą się .shskryptami Bash lub innym rozszerzeniem związanym z tym skryptem, co ma miejsce, jeśli generujesz skrypty za pomocą jakiegoś narzędzia szablonowego, takiego jak ERB (wtedy się kończą .erb). Głosuj na youtrack.jetbrains.com/issue/IDEA-79574, jeśli chcesz to naprawić!
Greg Dubicki
1

Jeśli potrzebujesz w zmiennej ważności wszystkich plików w katalogu (git pre-commit hook, build lint script), możesz złapać wyjście stderr komend „sh -n” lub „bash -n” (zobacz inne odpowiedzi) w zmiennej i na tej podstawie mieć „if / else”

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

Zmień „sh” na „bash” w zależności od potrzeb

Elvis Ciotti
źródło