ShellCheck: Kabuk betiği hatalarını bulan analiz aracı
(shellcheck.net)- ShellCheck, yaygın kabuk betiği hatalarını doğrudan web üzerinde denetleyebilen bir araçtır; yapıştırdığınız koddaki sorunları düzenleyicinin altındaki çıktı bölümünde görebilirsiniz
- Yerel ortamda
cabal,apt,dnf,pkg,brew installgibi yöntemlerle kurulabilir; bu da paket yöneticisi tabanlı kullanım sağlar - Örnekler,
shshebang için taşınabilirlik uyarıları, anlamsal sorunlar ve tırnak işleme hataları gibi gerçek betiklerde sıkça gözden kaçan noktaları gösterir - GPLv3 lisanslı özgür bir yazılımdır ve GitHub, Wiki ile başlıca editörlerde entegre linter olarak da sunulur
- CodeClimate, Codacy ve CodeFactor üzerinde GitHub depolarının otomatik denetiminde kullanılabilir; ShellCheck’in kendisi ise Haskell ile yazılmıştır
Kabuk betiği analiz özellikleri
- ShellCheck, kabuk betiklerinde hata bulan bir analiz aracıdır
- Betiği web sitesine yapıştırdığınızda, düzenleyicinin altındaki çıktı penceresinde denetim sonuçlarını hemen görebilirsiniz
- Dahil edilen örnekler, birçok farklı türde sorunun tespit edilebildiğini gösterir
- Sıradan betiklerde gizli kalan çeşitli sorunlar
- shebang
sholduğunda ortaya çıkan taşınabilirlik uyarıları - Daha üst düzey anlamsal sorunlar
- Çeşitli tırnak işleme sorunları
Kurulum, lisans ve entegrasyon
- Yerel kurulum
cabal,apt,dnf,pkg,brew installile yapılabilir - GPLv3 lisanslı özgür bir yazılımdır
- Belgeler ShellCheck Wiki üzerinde bulunabilir
- GitHub üzerinde açık olarak yayımlanmıştır; web sitesi kodu da birlikte açıktır
- Dağıtımlar veya paket yöneticileri için paketler zaten sunulmaktadır
- Başlıca editörlerde entegre linter olarak kullanılabilir
- CodeClimate, Codacy, CodeFactor üzerinde GitHub depolarının otomatik denetiminde kullanılabilir
- ShellCheck, Haskell ile yazılmıştır
1 yorum
Hacker News görüşleri
Benim kullandığım ipuçları şöyle. shebang içinde neredeyse her zaman
-u(nounset) koyup tanımlanmamış değişkenleri hata haline getirmek iyi olur; sık karşılaşılan istisna ise"${arr[@]}"söz dizimiyle boş bir diziyi genişletirken bunun unbound olarak değerlendirilmesi-n(noexec) komutların çalıştırılmasını engellediği için yoksul işi bir dry-run gibi kullanılabilir.-e(errexit) de yararlıdır ama pratikte yalnızca başarısız olan “o komutun kendisi” çıkışa yol açar; buna dikkat etmek gerektiğinden ben şahsen bundan kaçınıp komutların arkasına sık sık|| fail "..."eklemeyi tercih ediyorum"${arr[@]}"sorunu yalnızca bash 3 ve öncesinde var; bash 4'ten itibaren değişken gerçekten tanımlanmamış olsa bile[@]unbound variable fırlatmıyorYine de macOS hâlâ varsayılan olarak bash v3 kurduğu ve otomatik güncellemediği için bu sorun sürüyor. bash 3'ün son sürümünün 20 yıl önce çıkmış olması gerçekten akıl almaz. Boş dizi genişletmesinde unbound oluşması
${var+alter}genişletmesiyle aşılabilir:echo "${arr+${arr[@]}}"./my_script.shyerinebash my_script.shgibi yorumlayıcıyı açıkça belirterek çalıştırırsa seçenekler uygulanmazÇalıştırma bitini ayarlamamak için bunu yapan epey kişi var; bazen de sebep konuyu yeterince anlamamak oluyor. Bu yüzden shebang'den sonraki ilk satıra
set -euo pipefailgibi birsetyazılması sık önerilir; ayrıca#!/usr/bin/env bashgibi shebang'in ek argümanları ele almakta zorlandığı durumlarda da işe yarar-uyu shebang'e koymanın özel bir nedeni var mı, merak ediyorum.set -uyerine neden shebang?Bash'te
"${arr[@]}"düzgün çalışıyor gibi görünüyor. Diğer yorumlarda da belirtildiği gibi güncel Bash'te daha da iyileşmiş ve sorun yalnızca<= 4.3için geçerli gibi: https://news.ycombinator.com/item?id=38397241Örneğin
bash -uc 'unset x; echo "=> ${x[@]}"'vebash -uc 'x=(); echo "=> ${x[@]}"'boş değerle geçiyor, amabash -uc 'x=(); echo "=> ${x[0]}"'komutubash: x[0]: unbound variablebırakıyor. Zsh ilk örneği sevmiyor ama ikisi debash -uc 'unset x; echo "=> ${x[@]:-null}"'gibi varsayılan değer genişletmesini desteklemeli.-e, fonksiyonlarla birleşince çok kafa karıştırıcı hale geliyor; yıllar geçtikçe daha az seviyorum-esorunu-o pipefailile iyi yönetilebilir; bu da geçen yıldan beri POSIX'e dahiltrapde kullanmak gerekiyordutrapharika bir betik yazma özelliği, ama bana kalırsa hakkında yeterince konuşulmuyorYakın zamanda aritmetik genişletme nedeniyle bir shell script'te yetki yükseltme açığı buldum. https://research.nccgroup.com/2020/05/12/shell-arithmetic-ex... adresindekine benzer bir tür
Örneğin
$((1 + ENV_VAR)),$ENV_VARüzerinde kontrolünüz varsa kod enjeksiyonuna izin verebilir. Ne yazık ki ShellCheck bunu en azından varsayılan ayarlarla yakalayamadı. Ama güvenlik açısından az da olsa önemli bir şey geliştiriyorsanız zaten baştan shell kullanmamalısınızShellCheck gerçekten kurtarıcı. Daha önce küçük bir sarmalayıcı olan https://github.com/jamespwilliams/strictbash'i yapmıştım; betiğin shebang'i olarak kullanılabiliyor
Betik çalışmadan önce ShellCheck'i çalıştırıyor; hata varsa betik hiç çalıştırılmıyor ve bash'in “strict mode” bayraklarının tamamını da ayarlıyor. Referans: http://redsymbol.net/articles/unofficial-bash-strict-mode/
Bu konu birkaç kez gündeme geldi: https://news.ycombinator.com/from?site=shellcheck.net
Son büyük tartışma 2021'deydi; 301 puan ve 54 yorum vardı: https://news.ycombinator.com/item?id=27030504
Kısa süre önce derleme ve dağıtım betiklerini, ayrıca tek bir üretim sunucusu için birkaç bash betiğini Haskell’in Turtle’ına taşıdım
Tekrarı ciddi ölçüde azaltabildiğim için iyiydi; ortaya çıkan kod da çok daha kısa oldu. https://hackage.haskell.org/package/turtle
Bildiğim kadarıyla Turtle programlarında yalnızca tek bir geçerli dizin var; bu da belirli bir dizinde çalışması gereken eşzamanlı işleri yürütürken zorluk çıkarıyor. Kilit, kuyruk ve worker yaklaşımıyla bir kısmını çözdüm ama Turtle’ın geçerli dizini silinip işler hata vermeye başlayınca başa çıkmak zorlaştı
Buna karşılık typed-process ayrı süreçler başlatıyor ve
cdyapmaya gerek kalmadan çalışma dizini içinde çalıştırılabiliyor; bu yüzden büyük ve karmaşık iş akışlarına iyi uyuyor.OverloadedStringsdesteği de iyi, bu nedenle normalde bash’e yazacağınız şeyleri kopyalayıp yapıştırınca aynen çalışıyorHam string’leri kaynak kodda daha okunur kılmak için
interpolatepaketi veQuasiQuotesda kullanıyorum; ancakhlintile uyumlu olmadığı için string işleme için başka bir paket bakmayı düşünüyorumAçıkça öz tanıtım olacak ama commit’ten önce ya da en azından merge’den önce tüm uyarıları düzeltme ilkesiyle ShellCheck’i ve çeşitli linter’ları pre-commit yapılandırmama koyuyorum
Ancak projelerimin çoğundaki shell kodu
.gitlab-ci.ymldosyasının içinde olduğundan kontrol etmesi zor. Bu yüzden bunu otomatik yapan bir wrapper yazdım: https://pypi.org/project/glscpc/ShellCheck projesini ve biraz sihri kullanarak ShellCheck uyarılarını neredeyse doğru satır numaralarıyla gösteriyor
GitLab CI kullanmıyorum ama Dockerfile, GitHub Actions, Justfile gibi, özünde shell script’i satır içine gömen epey çok dosya biçimi kullanıyorum
Genelde, sırf ShellCheck için bile olsa birkaç komuttan daha karmaşık şeyleri ayrı bir shell script’e çıkarıp Dockerfile’daki satır içi betikten çağırıyorum. Bu kalıp, CI’ın GitHub Actions’a fazla sıkı bağlanmamasına da yardımcı oluyor
Kullanım örneği
.gitlab-ci.ymliçin bir pre-commit hook’u; yapılandırma örneği de burada: https://gitlab.com/engmark/root/-/blob/9f7d9b93c2297d0b170e5...scriptkısmı olarak render eden bir ön işleme eklemek istiyordumAvantajı, her şeyin hâlâ gitlab-ci işi içinde kendi kendine yeterli kalmasıydı. Ama GitLab CI runner ortamında shell’in her türlü acayipliğiyle uğraşmak çok eziyetli olduğu için bıraktım; şimdi tüm işleri Python script’lerine taşıyorum
bash language server da var: https://github.com/bash-lsp/bash-language-server/
Güzel. İlk kez çalıştırdığım üretim
/bin/shbetiğinde hemen birkaç şey öğrendim; oysa bu tür betiklerle 80’lerden beri uğraşıyorumBash ile yazmak için fazla uzayıp aslında öyle yapılmaması gereken bir durumdaysanız https://github.com/bach-sh/bach de tavsiye ederim
ShellCheck harika ama source/import işleme gerçekten acı verici. Bu ShellCheck’in suçu değil;
shbir kâbus olduğu için böyle# shellcheck source=./deployment/deployment-example.envyazıp ardından. "${1}"kullanmakAma çok sayıda alt shell script’i ve source edilecek dosya çoğaldığında bunun neden acı verici olduğunu anlıyorsunuz