ShellCheck: shell script bugs खोजने वाला analysis tool
(shellcheck.net)- ShellCheck एक ऐसा टूल है जिससे shell script की आम गलतियों को वेब पर तुरंत जांचा जा सकता है, और paste किए गए code की समस्याएं editor के नीचे output में देखी जा सकती हैं
- लोकल environment में इसे
cabal,apt,dnf,pkg,brew installआदि से install किया जा सकता है, इसलिए package manager आधारित उपयोग संभव है - उदाहरण
shshebang की portability warning, semantic issues, और quote handling errors जैसी उन जगहों को दिखाते हैं जो असली scripts में अक्सर छूट जाती हैं - यह GPLv3 लाइसेंस वाला free software है, और GitHub, Wiki, तथा प्रमुख editors के integrated linter के रूप में भी उपलब्ध है
- इसे CodeClimate, Codacy, और CodeFactor में GitHub repositories की automatic checking के लिए इस्तेमाल किया जा सकता है, और ShellCheck खुद Haskell में लिखा गया है
shell script analysis सुविधाएं
- ShellCheck, shell scripts में bugs खोजने वाला analysis tool है
- वेबसाइट पर script paste करने पर editor के नीचे output window में check results तुरंत देखे जा सकते हैं
- शामिल उदाहरण दिखाते हैं कि यह कई तरह की समस्याएं detect कर सकता है
- आम scripts में छिपी कई समस्याएं
- shebang
shहोने पर आने वाली portability warnings - अधिक उच्च-स्तरीय semantic issues
- अलग-अलग quote handling problems
installation, लाइसेंस, integration
- लोकल installation
cabal,apt,dnf,pkg,brew installसे संभव है - यह GPLv3 लाइसेंस वाला free software है
- दस्तावेज़ ShellCheck Wiki पर देखे जा सकते हैं
- यह GitHub पर public है, और website code भी साथ में public है
- distributions या package managers के लिए packages पहले से उपलब्ध हैं
- प्रमुख editors में इसे integrated linter के रूप में इस्तेमाल किया जा सकता है
- CodeClimate, Codacy, CodeFactor में GitHub repositories की automatic checking के लिए इसका उपयोग किया जा सकता है
- ShellCheck Haskell में लिखा गया है
1 टिप्पणियां
Hacker News की रायें
मेरा इस्तेमाल किया जाने वाला tip यह है। shebang में लगभग हमेशा
-u(nounset) डालना बेहतर होता है, ताकि घोषित न किए गए variables को error बनाया जा सके; जो exception अक्सर दिखता है वह"${arr[@]}"syntax से empty array expand करते समय unbound माना जाना है-n(noexec) command execution रोकता है, इसलिए इसे गरीब आदमी के dry-run की तरह इस्तेमाल किया जा सकता है।-e(errexit) भी उपयोगी है, लेकिन ध्यान रखना पड़ता है कि व्यवहार में सिर्फ fail हुई “वही” command exit trigger करती है, इसलिए मैं व्यक्तिगत तौर पर इसे avoid करता हूं और commands के बाद अक्सर|| fail "..."जोड़ना पसंद करता हूं"${arr[@]}"वाली समस्या सिर्फ bash 3 या उससे पुराने में है, और bash 4 से, variable सच में defined न हो तब भी[@]unbound variable नहीं फेंकताफिर भी macOS अब भी default रूप से bash v3 install करता है और auto-update भी नहीं करता, इसलिए यह समस्या बनी हुई है। bash 3 की आखिरी release 20 साल पहले हुई थी, यह सच में पागलपन है। empty array expansion में unbound आने को
${var+alter}expansion से bypass किया जा सकता है:echo "${arr+${arr[@]}}"./my_script.shकी बजायbash my_script.shकी तरह interpreter स्पष्ट करके चलाता है, तो options apply नहीं होतेexecutable bit set न करने के लिए काफी लोग ऐसा करते हैं, और कभी-कभी वजह समझ की कमी भी होती है। इसलिए shebang के बाद पहली line में
set -euo pipefailजैसाsetइस्तेमाल करने की सलाह आम है, और#!/usr/bin/env bashजैसे cases में भी मदद मिलती है जहां shebang के लिए extra arguments संभालना कठिन होता है-uको shebang में डालने की कोई खास वजह है क्या।set -uके बजाय shebang क्यों?Bash में
"${arr[@]}"ठीक काम करता लगता है। जैसा दूसरे comments में भी बताया गया, नए Bash में यह और बेहतर हुआ है, और समस्या सिर्फ<= 4.3में दिखती है: https://news.ycombinator.com/item?id=38397241उदाहरण के लिए
bash -uc 'unset x; echo "=> ${x[@]}"'औरbash -uc 'x=(); echo "=> ${x[@]}"'empty value के साथ pass हो जाते हैं, लेकिनbash -uc 'x=(); echo "=> ${x[0]}"'मेंbash: x[0]: unbound variableरह जाता है। Zsh पहले example को पसंद नहीं करता, लेकिन दोनों कोbash -uc 'unset x; echo "=> ${x[@]:-null}"'की तरह default value expansion support करना चाहिए।-efunctions के साथ जुड़ने पर बहुत confusing हो जाता है, इसलिए समय के साथ मुझे यह कम पसंद आने लगा है-eकी समस्या-o pipefailसे अच्छी तरह संभाली जा सकती है, और यह पिछले साल से POSIX में शामिल हैtrapभी इस्तेमाल करना पड़ता थाtrapएक शानदार scripting feature है, लेकिन लगता है इसके बारे में पर्याप्त बात नहीं होतीहाल में arithmetic expansion की वजह से shell script में privilege escalation vulnerability मिली। यह https://research.nccgroup.com/2020/05/12/shell-arithmetic-ex... में बताए गए type जैसी थी
उदाहरण के लिए
$((1 + ENV_VAR))में अगर$ENV_VARको control किया जा सके तो code injection संभव है। दुर्भाग्य से ShellCheck ने कम से कम default settings में इसे नहीं पकड़ा। लेकिन अगर आप security के लिहाज से जरा भी महत्वपूर्ण कुछ implement कर रहे हैं, तो शुरुआत से ही shell इस्तेमाल नहीं करना चाहिएShellCheck सच में उद्धारकर्ता है। पहले मैंने एक छोटा wrapper https://github.com/jamespwilliams/strictbash बनाया था, जिसे scripts के shebang के तौर पर इस्तेमाल किया जा सकता है
script चलने से पहले ShellCheck चलाता है, और अगर failures हों तो script बिल्कुल execute नहीं होती, साथ ही bash के सभी “strict mode” flags भी set करता है। संदर्भ: http://redsymbol.net/articles/unofficial-bash-strict-mode/
यह विषय कई बार आ चुका है: https://news.ycombinator.com/from?site=shellcheck.net
आखिरी बड़ी चर्चा 2021 में हुई थी, 301 points और 54 comments थे: https://news.ycombinator.com/item?id=27030504
कुछ समय पहले build और deployment scripts, और single production server के लिए कुछ bash scripts को Haskell के Turtle में बदल दिया था
duplication काफी घटा सका, यह अच्छा लगा, और final code भी बहुत छोटा हो गया। https://hackage.haskell.org/package/turtle
मेरी जानकारी में Turtle program के पास सिर्फ एक current directory होती है, इसलिए ऐसे concurrent tasks चलाते समय मुश्किल होती है जिन्हें किसी खास directory में run होना चाहिए। locking, queue और worker approach से कुछ हद तक हल किया, लेकिन जब Turtle की current directory delete होने की वजह से failures शुरू हुए तो संभालना मुश्किल हो गया
इसके उलट typed-process अलग process launch करता है, और
cdकिए बिना working directory के अंदर run कर सकता है, इसलिए बड़े और complex workflows के लिए अच्छा fit है।OverloadedStringssupport भी अच्छा है, इसलिए आम तौर पर bash में जो type करते, उसे copy-paste करें तो वैसा ही काम करता हैraw strings को source code में बेहतर दिखाने के लिए
interpolatepackage औरQuasiQuotesभी इस्तेमाल करता हूं, लेकिन यहhlintके compatible नहीं है, इसलिए strings handling के लिए कोई और package देखने का सोच रहा हूंसाफ-साफ self-promotion है, लेकिन commit से पहले या कम से कम merge से पहले सारी warnings ठीक करता हूं—इस principle के साथ ShellCheck और कई linters को pre-commit setup में डाल रखा है
लेकिन मेरे ज्यादातर projects में shell
.gitlab-ci.ymlfiles के अंदर होता है, इसलिए check करना मुश्किल है। इसलिए इसे automatically handle करने वाला wrapper बनाया: https://pypi.org/project/glscpc/ShellCheck project और थोड़ी magic के साथ, लगभग सही line numbers के साथ ShellCheck की findings दिखाता है
GitLab CI इस्तेमाल नहीं करता, लेकिन Dockerfile, GitHub Actions, Justfile जैसे file formats काफी इस्तेमाल करता हूं, जिनमें मूल रूप से shell script inline डाली जाती है
आम तौर पर ShellCheck के लिए ही सही, कुछ commands से ज्यादा complex चीजों को अलग shell script में निकाल देता हूं और Dockerfile की inline script से उसे call कराता हूं। यह pattern CI को GitHub Actions से बहुत ज्यादा बंधने से बचाने में भी मदद करता है
usage example
.gitlab-ci.ymlके लिए pre-commit hook है, और configuration example यहां है: https://gitlab.com/engmark/root/-/blob/9f7d9b93c2297d0b170e5...scriptहिस्से में render करेफायदा यह था कि सब कुछ अब भी gitlab-ci job के अंदर self-contained रहता। लेकिन GitLab CI runner environment में shell की तमाम अजीबोगरीब चीजों से निपटना बहुत दर्दनाक था, इसलिए बंद कर दिया, और अब सारे jobs को Python script में shift कर रहा हूं
bash language server भी है: https://github.com/bash-lsp/bash-language-server/
अच्छा है। पहली बार run किए गए production
/bin/shscript से तुरंत कुछ चीजें सीखीं, जबकि ऐसे scripts 80s से संभालता आया हूंअगर Bash में लिखने के लिए इतना लंबा हो रहा है कि असल में ऐसा करना ही नहीं चाहिए, तो https://github.com/bach-sh/bach भी recommend करूंगा
ShellCheck शानदार है, लेकिन source/import handling सच में painful है। यह ShellCheck की गलती नहीं है,
shही nightmare है# shellcheck source=./deployment/deployment-example.envके बाद. "${1}"इस्तेमाल करेंहालांकि जब कई sub-shell scripts और source करने वाली files बढ़ जाती हैं, तो समझ आ जाता है कि यह क्यों painful है