Bir Bash betiğini çalıştırmadan nasıl söz dizimini kontrol edebilirim?


Yanıtlar:


380
bash -n scriptname

Belki bariz bir uyarı: Bu geçerli kılınarak sözdizimi ancak bash komut çalışır gibi, yoldaki olmayan bir komutu çalıştırmak için kontrol olmayacaktır ech helloyerine echo hello.


9
Bash'ın man sayfasında, "SHELL BUILTIN COMMANDS / set" altında, -n belgelenir ve manpage'in başlangıcı olarak bash, yapan tüm tek karakterli seçenekleri yorumlar set.
ephemient

24
(benim için) belirgin olmayan uyarıya eklemek için, if ["$var" == "string" ]bunun yerine eksik bir alanın neden olduğu bir hatayı yakalamazif [ "$var" == "string" ]
Brynjar

11
@Brynjar Çünkü sadece sözdizimi denetimi. Açık parantez sözdizimi değildir, çalıştırılacak işlevin adı budur. type ["[bir kabuk yerleşiktir” der. Sonunda testprograma delege eder , ancak bir kapanış parantezini de bekler. Yani bu if test"$var", yazarın kastettiği gibi değil, sözdizimsel olarak geçerlidir ($ var'ın "a" değerine sahip olduğunu varsayalım, o zaman "bash: testa: command not found"). Mesele şu, sözdizimsel olarak, eksik alan yoktur.
Joshua Cheek

2
@JoshuaCheek: Yerleşik [yalnızca bu durumda boş bir dizeye$var genişletilirse çağrılır . Eğer bir karşı genişleyeceği boş olmayan dize, bir birleştirilmiş bu dize ile ve bir olarak yorumlanır komut adı (değil işlevi olan Bash, ve, evet, tarafından adı) sözdizimsel belli ki devlet olarak, niyet geçerli değildir, ancak. Eğer kullanırsanız yerine , olsa bile bir kabuk anahtar kelime (yerine bir yerleşiğine yerine) istenmeyen bir dizge birleştirme hala anahtar kelimenin tanınmasını geçersiz kılar, çünkü, aynı sonucu elde edersiniz. $var[[[[[[
mklement0

2
@JoshuaCheek: Bash hala edilir sözdizimini burada kontrol ediliyor: o kontrol ediyor basit komut çağırma sözdizimi: ["$var"olan sözdizimsel geçerli bir komut adı ifadesi; benzer şekilde, jetonlar ==ve "$string"geçerli komut bağımsız değişkenleridir . (Genel olarak, yerleşik [ile ayrıştırılır komut ise, söz dizimi [[- bir kabuk olarak anahtar kelime - farklı ayrıştırılır.) Kabuk yerleşik [etmez olmayan temsilci "için testbir program" (dış faydalı) bash, dash, ksh, zshher şeye sahip yerleşik hem de alternatifler [vetestVe onlar yapmak değilharici yardımcı meslektaşlarını arayın.
mklement0

127

Zaman her şeyi değiştirir. İşte bir web sitesi kabuk betiği için çevrimiçi sözdizimi denetimi sağlayan .

Sık karşılaşılan hataları algılamanın çok güçlü olduğunu gördüm.

resim açıklamasını buraya girin

ShellCheck Hakkında

ShellCheck sh / bash betikleri için statik bir analiz ve linting aracıdır. Temel olarak, kabuğun sadece şifreli bir hata mesajı veya garip davranış verdiği tipik başlangıç ​​ve orta düzey sözdizimi hatalarını ve tuzaklarını ele almaya odaklanır, ancak köşe vakalarının gecikmiş hatalara neden olabileceği birkaç daha gelişmiş sorunu da bildirir.

Haskell kaynak kodu GitHub'da!


5
Büyük ipucu; OSX'te artık Homebrew : shellchecküzerinden shellcheck.net CLI'yi de yükleyebilirsiniz . brew install shellcheck
mklement0

3
Ayrıca debian ve arkadaşlarında:apt-get install shellcheck
diğer adam

Ubuntu güvenilir için bu paketin yüklenmesi gerekir trusty-backports.
Peterino

Yukarıda belirtildiği gibi, güvenilir bağımlılık gerekli ve ubuntu 14.04'te aşağıdaki gibi yükleyebilirsiniz: sudo apt-get -f install, o zaman: sudo sudo apt-get install shellcheck
zhihong

Bu gerçekten yararlıdır, ancak Bash'in ayrıştırıcısını değil, kendi çözümleyicisini kullanır. Çoğu durumda bu yeterince iyidir ve hem ayrıştırma hem de diğer sorunları tanımlayabilir, ancak aynı şekilde ayrıştırılmadığı en az bir kenar durumu (ve muhtemelen görmediğim diğerleri) vardır.
Daniel H

38

Ayrıca, bazı ekstra kontroller yapmak için yazdığım her bash betiğinde 'u' seçeneğini etkinleştiriyorum:

set -u 

Bu, şu komut dosyasında olduğu gibi başlatılmamış değişkenlerin kullanımını bildirir. 'Check_init.sh'

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

Komut dosyasını çalıştırma:

$ check_init.sh

Aşağıdakileri rapor edecektir:

./check_init.sh[4]: mesage: Parametre ayarlanmadı.

Yazım hatalarını yakalamak için çok yararlı


4
Bu bayrakları her zaman bash scriptlerimde ayarladım, eğer bunları geçerse, "set -o errexit" "set -o nounset" "set -o pipefail" e gitmek iyi
μολὼν.λαβέ 10:30 '

set -uHata iletisini almak için komut dosyasını çalıştırmanız gerektiğinden, bu soruyu gerçekten yanıtlamasa da +1 . bash -n check_init.shBu uyarıyı bile göstermiyor
rubo77

23
sh  -n   script-name 

Bunu çalıştırın. Kodda herhangi bir sözdizimi hatası varsa, aynı hata iletisini döndürür. Hata yoksa, herhangi bir mesaj vermeden ortaya çıkar. Kullanarak hemen kontrol edebilirsiniz echo $?, bu da 0başarılı bir şekilde onaylamayı herhangi bir hata yapmadan geri döndürür .

Benim için iyi çalıştı. Linux işletim sistemi, Bash Shell üzerinde çalıştım.


1
Bas sözdizimi denetimi ile tam olarak ilgili olmasa da - komut dosyasının tüm bölümlerinde veya bölümlerinde hata ayıklamak için set -x ve set + x kullanmak oldukça yararlıdır
GuruM

Bunun için teşekkürler bilmiyordum -n hakkında bilmiyordum ama istediğim @GuruM> sh -x test.sh betiğin oluşturulan çıktısını görüntüler gibi
zzapper

1
Evet. Aşağıdakileri yapabileceğinizi belirtmeyi unuttum: Komut satırında: 1) bash -x test.sh #Bu komut dosyasını 'hata ayıklama modunda' çalıştırır 2) set + x; bash testi.sh; komut dosyası çalıştırılmadan önce / sonra -x #set hata ayıklama modunu ayarla / kapat komut dosyasında: a) #! / bin / bash -x # betiğin üstüne 'hata ayıklama modu' ekle b) set + x; kod; script herhangi bir bölüm için -x #add 'ayıklama modu' set
GuruM

sh -nmuhtemelen betiğin geçerli Bash betiği olup olmadığını kontrol etmez. Yanlış negatifler verebilir. shgenellikle Bash olmayan bazı Bourne kabuğu varyantıdır. Örneğin Ubuntu Linux'tarealpath -e $(command -v sh) / bin / dash
jarno

4

Aslında findaracı kullanarak çalıştırmadan OLMADAN sözdizimi hataları için geçerli dir tüm bash komut dosyaları kontrol :

Misal:

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

Tek bir dosya için kullanmak istiyorsanız, joker karakteri dosyanın adıyla düzenleyin.


3

null komutu [iki nokta] değişkenin değerini görmek için hata ayıklama sırasında da kullanışlıdır

set -x
for i in {1..10}; do
    let i=i+1
    : i=$i
done
set - 

parametre genişletmeleri kullanır
mug896

Bu çalışır, çünkü set -xyürütülmeden önce her satırı gösterir
rubo77


1

Bir dizindeki tüm dosyaların geçerliliğine ihtiyacınız varsa (git pre-commit hook, build lint script), "sh -n" veya "bash -n" komutlarının stderr çıktısını yakalayabilirsiniz (diğerlerine bakın) cevaplar) bir değişkeni kullanın ve buna dayalı bir "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

İhtiyaçlarınıza göre "sh" i "bash" ile değiştirin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.