shell-script-quality
Skill2 starsChanged 9 days agoMITView on GitHub
Lint and test shell scripts using ShellCheck and BATS. Use this skill when checking bash/sh scripts for errors, writing shell script tests, fixing ShellCheck warnings, setting up CI/CD for shell scripts, or improving bash code quality — even if they just say "fix this script" or "add tests for the shell script". Not for static-analysis, cicd-pipeline.
- Installs packages
In this repository63 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .agents/skills/avoid-ai-writing/AGENTS.mdAGENTS.md
- .agents/skills/do-web-doc-resolver/AGENTS.mdAGENTS.md
- .agents/skills/skill-evaluator/AGENTS.mdAGENTS.md
- scripts/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llms-full.txtllms.txt
- llms.txtllms.txt
- accessibility-auditorSkill
- agent-browserSkill
- agentic-abstentionSkill
- agents-mdSkill
- api-design-firstSkill
- architecture-diagramSkill
- avoid-ai-writingSkill
- cicd-pipelineSkill
- cloudflare-worker-apiSkill
- codacySkill
- codeberg-apiSkill
- code-review-assistantSkill
- css-render-performanceSkill
- database-devopsSkill
- debuggerSkill
- delegateSkill
- dependency-upgradesSkill
- dist-channel-selectionSkill
- docs-hookSkill
- document-rendering-and-locatorsSkill
- dogfoodSkill
- dora-reportSkill
- do-web-doc-resolverSkill
- durable-objectsSkill
- eu-ai-act-complianceSkill
- git-github-workflowSkill
- goap-agentSkill
- implementerSkill
- intent-classifierSkill
- iterative-refinementSkill
- jules-delegatorSkill
- learnSkill
- lifecycle-managementSkill
- local-context-sanitizationSkill
- memory-contextSkill
- migration-refactoringSkill
- nested-build-isolationSkill
- privacy-firstSkill
- progressive-deliverySkill
- pwa-offline-syncSkill
- reader-ui-uxSkill
- readme-best-practicesSkill
- secrets-managementSkill
- secure-invite-and-accessSkill
- security-code-auditorSkill
- skill-creatorSkill
- skill-evaluatorSkill
- static-analysisSkill
- testing-strategySkill
- test-runnerSkill
- triz-solverSkill
- turso-dbSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 36
Note: When searching for patterns across scripts, use the dedicated Grep Tool (with pattern/type parameters) instead of calling grep or …
- Very specific: line 52
required: check has issueThreshold: 0 and counts issues at *any* severity.
- Distinctive: line 208
If fails: review errors, fix, re-run.
- Very specific: line 209
Only proceed when validation passes → bats tests/script.bats.
- Distinctive: line 210
If tests fail, return to step 1.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Shell Script Quality
Comprehensive shell script linting and testing using ShellCheck and BATS with 2025 best practices.
When to Use
- User asks to check bash/sh scripts for errors or fix ShellCheck warnings
- Need to write shell script tests or set up CI/CD for shell scripts
- Even if they just say "fix this script" or "add tests for the shell script"
Quick Start
Copy this workflow checklist and track your progress:
Shell Script Quality Workflow:
- [ ] Step 1: Lint with ShellCheck
- [ ] Step 2: Fix reported issues
- [ ] Step 3: Write BATS tests
- [ ] Step 4: Verify tests pass
- [ ] Step 5: Integrate into CI/CDCore Workflow
Step 1: Lint with ShellCheck
Note: When searching for patterns across scripts, use the dedicated Grep Tool (with pattern/type parameters) instead of calling grep or find directly, as per AGENTS.md.
# Lint single file
shellcheck script.sh
# Lint all scripts
find scripts -name "*.sh" -exec shellcheck {} +
# Use config file if present
shellcheck -x script.shStep 1b: Verify new code at FULL severity (required before push)
This repo's quality_gate.sh runs shellcheck --severity=error, but Codacy's
required check has issueThreshold: 0 and counts issues at any severity.
Code that passes the local gate can therefore still block a merge. Verify the
files you touched at full severity, where all levels are findings:
# Full severity on the files you changed
shellcheck path/to/changed.sh
# Delta check: compare full severity between HEAD and your branch, so you only
# see NEW issues. A blanket repo-wide full-severity run is NOT viable here --
# ~127 pre-existing findings would drown the signal.
git stash -q
shellcheck $(git ls-files '*.sh') 2>&1 | grep -cE '^In |SC[0-9]+' > /tmp/opencode/sc-base
git stash pop -q
shellcheck $(git ls-files '*.sh') 2>&1 | grep -cE '^In |SC[0-9]+' > /tmp/opencode/sc-new
diff /tmp/opencode/sc-base /tmp/opencode/sc-new && echo "no new findings"Query the real verdict rather than guessing:
codacy pull-request <PR> -o json # newIssues, quality.gate, per-issue resultDataIdTwo codes that found real defects here, and are worth reading as bugs rather than style:
| Code | Why it matters |
SC2235 | (...) is a subshell. VAR+=(x) inside it never reaches the parent, so a later [[ " ${VAR[*]} " =~ " x " ]] test silently never matches — a latent false green. |
SC2034 | "Appears unused" across a source boundary is usually a real contract: the variable is read by the sourcing script. Fix with a file-scope disable plus a stated reason, or fix the contract. |
Common fixes: See SHELLCHECK.md for fix patterns
Step 2: Fix Reported Issues
Apply fixes for common warnings:
- SC2086: Quote variables:
"$var"not$var - SC2155: Separate declaration and assignment
- SC2181: Check exit code directly with
if ! command
For detailed fixes: See SHELLCHECK.md
Step 3: Write BATS Tests
#!/usr/bin/env bats
setup() {
source "$BATS_TEST_DIRNAME/../scripts/example.sh"
}
@test "function succeeds with valid input" {
run example_function "test"
[ "$status" -eq 0 ]
[ -n "$output" ]
}
@test "function fails with invalid input" {
run example_function ""
[ "$status" -ne 0 ]
[[ "$output" =~ "ERROR" ]]
}Test patterns: See BATS.md for comprehensive testing guide
Step 4: Run Tests
# Run all tests
bats tests/
# Run with verbose output
bats -t tests/
# Run specific file
bats tests/example.batsIf tests fail: Review error output, fix issues, re-run validation
Step 5: CI/CD Integration
GitHub Actions: See CI-CD.md for complete workflows
Quick integration:
On an Ubuntu runner after checkout, install the tools rather than using a third-party action on a mutable branch. Adapt the script paths to the project.
- name: Install shell checks
run: |
sudo apt-get update
sudo apt-get install -y shellcheck bats
- name: ShellCheck
run: shellcheck scripts/*.sh
- name: Run BATS
run: bats tests/Script Template
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
error_exit() { echo "ERROR: $1" >&2; exit "${2:-1}"; }
main() {
[[ $# -lt 1 ]] && { echo "Usage: $0 <argument>" >&2; exit 1; }
# Your logic here
}
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@"Installation
brew install shellcheck # macOS | sudo apt-get install shellcheck # Linux
brew install bats-core # macOS | sudo apt-get install bats # LinuxConfiguration
.shellcheckrc in project root: shell=bash, disable=SC1090, enable=all, source-path=SCRIPTDIR. See CONFIG.md.
Testing Claude Code Plugins
@test "plugin script works" {
export CLAUDE_PLUGIN_ROOT="$BATS_TEST_DIRNAME/.."
run bash "$CLAUDE_PLUGIN_ROOT/scripts/search.sh" "query"
[ "$status" -eq 0 ]
}
@test "hook provides suggestions" {
local input='{"tool":"Edit","params":{"file_path":"test.txt"}}'
run bash "$HOOK_DIR/pre-edit.sh" <<< "$input"
[ "$status" -eq 0 ]
echo "$output" | jq empty
}More patterns: See PATTERNS.md
Troubleshooting
- ShellCheck: SC1090 → add
# shellcheck source=path/to/file.sh. False positives →# shellcheck disable=SCxxxx. - BATS: Tests interfere → ensure proper
teardown(). Can't source → add main execution guard. Path issues → use$BATS_TEST_DIRNAME.
See TROUBLESHOOTING.md.
Validation Loop Pattern
- Make changes →
shellcheck script.shimmediately. - If fails: review errors, fix, re-run.
- Only proceed when validation passes →
bats tests/script.bats. - If tests fail, return to step 1.
References
- SHELLCHECK.md - Complete ShellCheck guide and fix patterns
- BATS.md - BATS testing comprehensive guide
- CI-CD.md - GitHub Actions, GitLab CI, pre-commit hooks
- PATTERNS.md - Common patterns and examples
- CONFIG.md - Configuration and setup details
- TROUBLESHOOTING.md - Common issues and solutions
See Also
static-analysis— Linter triage across any languagecicd-pipeline— CI/CD for shell script testing
Rationalizations
| Rationalization | Reality |
| "ShellCheck warnings are false positives" | Most SC warnings catch real bugs; suppress with documented reason, not dismissal. |
| "The local gate passed, so the code is clean" | The gate runs --severity=error; Codacy's required check counts issues at any severity. Warning-level findings pass locally and still block the merge. |
| "Just run full-severity ShellCheck on the whole repo" | ~127 findings already exist at full severity. Use a base-vs-branch delta so new issues are visible without the noise. |
| "BATS tests take too long to write" | Untested scripts break silently in production; test time is investment, not waste. |
| "set -e is too strict for my script" | Scripts without -e silently swallow errors and leave systems in inconsistent states. |
Red Flags
- Running shell scripts without set -euo pipefail
- Skipping ShellCheck linting before committing shell scripts
- Trusting
--severity=erroras proof of Codacy-clean shell code - Checking
codacy pull-requestonly after discovering the PR is blocked - Suppressing SC warnings without documenting the reason and date
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

