Master ShellCheck static analysis configuration and usage for shell script quality. Use when setting up linting infrastructure, fixing code issues, or ensuring script portability.
Add this skill
npx mdskills install sickn33/shellcheck-configurationComprehensive ShellCheck reference with excellent examples, error codes, and integration patterns
1---2name: shellcheck-configuration3description: Master ShellCheck static analysis configuration and usage for shell script quality. Use when setting up linting infrastructure, fixing code issues, or ensuring script portability.4---56# ShellCheck Configuration and Static Analysis78Comprehensive guidance for configuring and using ShellCheck to improve shell script quality, catch common pitfalls, and enforce best practices through static code analysis.910## Do not use this skill when1112- The task is unrelated to shellcheck configuration and static analysis13- You need a different domain or tool outside this scope1415## Instructions1617- Clarify goals, constraints, and required inputs.18- Apply relevant best practices and validate outcomes.19- Provide actionable steps and verification.20- If detailed examples are required, open `resources/implementation-playbook.md`.2122## Use this skill when2324- Setting up linting for shell scripts in CI/CD pipelines25- Analyzing existing shell scripts for issues26- Understanding ShellCheck error codes and warnings27- Configuring ShellCheck for specific project requirements28- Integrating ShellCheck into development workflows29- Suppressing false positives and configuring rule sets30- Enforcing consistent code quality standards31- Migrating scripts to meet quality gates3233## ShellCheck Fundamentals3435### What is ShellCheck?3637ShellCheck is a static analysis tool that analyzes shell scripts and detects problematic patterns. It supports:38- Bash, sh, dash, ksh, and other POSIX shells39- Over 100 different warnings and errors40- Configuration for target shell and flags41- Integration with editors and CI/CD systems4243### Installation4445```bash46# macOS with Homebrew47brew install shellcheck4849# Ubuntu/Debian50apt-get install shellcheck5152# From source53git clone https://github.com/koalaman/shellcheck.git54cd shellcheck55make build56make install5758# Verify installation59shellcheck --version60```6162## Configuration Files6364### .shellcheckrc (Project Level)6566Create `.shellcheckrc` in your project root:6768```69# Specify target shell70shell=bash7172# Enable optional checks73enable=avoid-nullary-conditions74enable=require-variable-braces7576# Disable specific warnings77disable=SC109178disable=SC208679```8081### Environment Variables8283```bash84# Set default shell target85export SHELLCHECK_SHELL=bash8687# Enable strict mode88export SHELLCHECK_STRICT=true8990# Specify configuration file location91export SHELLCHECK_CONFIG=~/.shellcheckrc92```9394## Common ShellCheck Error Codes9596### SC1000-1099: Parser Errors97```bash98# SC1004: Backslash continuation not followed by newline99echo hello\100world # Error - needs line continuation101102# SC1008: Invalid data for operator `=='103if [[ $var = "value" ]]; then # Space before ==104 true105fi106```107108### SC2000-2099: Shell Issues109110```bash111# SC2009: Consider using pgrep or pidof instead of grep|grep112ps aux | grep -v grep | grep myprocess # Use pgrep instead113114# SC2012: Use `ls` only for viewing. Use `find` for reliable output115for file in $(ls -la) # Better: use find or globbing116117# SC2015: Avoid using && and || instead of if-then-else118[[ -f "$file" ]] && echo "found" || echo "not found" # Less clear119120# SC2016: Expressions don't expand in single quotes121echo '$VAR' # Literal $VAR, not variable expansion122123# SC2026: This word is non-standard. Set POSIXLY_CORRECT124# when using with scripts for other shells125```126127### SC2100-2199: Quoting Issues128129```bash130# SC2086: Double quote to prevent globbing and word splitting131for i in $list; do # Should be: for i in $list or for i in "$list"132 echo "$i"133done134135# SC2115: Literal tilde in path not expanded. Use $HOME instead136~/.bashrc # In strings, use "$HOME/.bashrc"137138# SC2181: Check exit code directly with `if`, not indirectly in a list139some_command140if [ $? -eq 0 ]; then # Better: if some_command; then141142# SC2206: Quote to prevent word splitting or set IFS143array=( $items ) # Should use: array=( $items )144```145146### SC3000-3999: POSIX Compliance Issues147148```bash149# SC3010: In POSIX sh, use 'case' instead of 'cond && foo'150[[ $var == "value" ]] && do_something # Not POSIX151152# SC3043: In POSIX sh, use 'local' is undefined153function my_func() {154 local var=value # Not POSIX in some shells155}156```157158## Practical Configuration Examples159160### Minimal Configuration (Strict POSIX)161162```bash163#!/bin/bash164# Configure for maximum portability165166shellcheck \167 --shell=sh \168 --external-sources \169 --check-sourced \170 script.sh171```172173### Development Configuration (Bash with Relaxed Rules)174175```bash176#!/bin/bash177# Configure for Bash development178179shellcheck \180 --shell=bash \181 --exclude=SC1091,SC2119 \182 --enable=all \183 script.sh184```185186### CI/CD Integration Configuration187188```bash189#!/bin/bash190set -Eeuo pipefail191192# Analyze all shell scripts and fail on issues193find . -type f -name "*.sh" | while read -r script; do194 echo "Checking: $script"195 shellcheck \196 --shell=bash \197 --format=gcc \198 --exclude=SC1091 \199 "$script" || exit 1200done201```202203### .shellcheckrc for Project204205```206# Shell dialect to analyze against207shell=bash208209# Enable optional checks210enable=avoid-nullary-conditions,require-variable-braces,check-unassigned-uppercase211212# Disable specific warnings213# SC1091: Not following sourced files (many false positives)214disable=SC1091215216# SC2119: Use function_name instead of function_name -- (arguments)217disable=SC2119218219# External files to source for context220external-sources=true221```222223## Integration Patterns224225### Pre-commit Hook Configuration226227```bash228#!/bin/bash229# .git/hooks/pre-commit230231#!/bin/bash232set -e233234# Find all shell scripts changed in this commit235git diff --cached --name-only | grep '\.sh$' | while read -r script; do236 echo "Linting: $script"237238 if ! shellcheck "$script"; then239 echo "ShellCheck failed on $script"240 exit 1241 fi242done243```244245### GitHub Actions Workflow246247```yaml248name: ShellCheck249250on: [push, pull_request]251252jobs:253 shellcheck:254 runs-on: ubuntu-latest255256 steps:257 - uses: actions/checkout@v3258259 - name: Run ShellCheck260 run: |261 sudo apt-get install shellcheck262 find . -type f -name "*.sh" -exec shellcheck {} \;263```264265### GitLab CI Pipeline266267```yaml268shellcheck:269 stage: lint270 image: koalaman/shellcheck-alpine271 script:272 - find . -type f -name "*.sh" -exec shellcheck {} \;273 allow_failure: false274```275276## Handling ShellCheck Violations277278### Suppressing Specific Warnings279280```bash281#!/bin/bash282283# Disable warning for entire line284# shellcheck disable=SC2086285for file in $(ls -la); do286 echo "$file"287done288289# Disable for entire script290# shellcheck disable=SC1091,SC2119291292# Disable multiple warnings (format varies)293command_that_fails() {294 # shellcheck disable=SC2015295 [ -f "$1" ] && echo "found" || echo "not found"296}297298# Disable specific check for source directive299# shellcheck source=./helper.sh300source helper.sh301```302303### Common Violations and Fixes304305#### SC2086: Double quote to prevent word splitting306307```bash308# Problem309for i in $list; do done310311# Solution312for i in $list; do done # If $list is already quoted, or313for i in "${list[@]}"; do done # If list is an array314```315316#### SC2181: Check exit code directly317318```bash319# Problem320some_command321if [ $? -eq 0 ]; then322 echo "success"323fi324325# Solution326if some_command; then327 echo "success"328fi329```330331#### SC2015: Use if-then instead of && ||332333```bash334# Problem335[ -f "$file" ] && echo "exists" || echo "not found"336337# Solution - clearer intent338if [ -f "$file" ]; then339 echo "exists"340else341 echo "not found"342fi343```344345#### SC2016: Expressions don't expand in single quotes346347```bash348# Problem349echo 'Variable value: $VAR'350351# Solution352echo "Variable value: $VAR"353```354355#### SC2009: Use pgrep instead of grep356357```bash358# Problem359ps aux | grep -v grep | grep myprocess360361# Solution362pgrep -f myprocess363```364365## Performance Optimization366367### Checking Multiple Files368369```bash370#!/bin/bash371372# Sequential checking373for script in *.sh; do374 shellcheck "$script"375done376377# Parallel checking (faster)378find . -name "*.sh" -print0 | \379 xargs -0 -P 4 -n 1 shellcheck380```381382### Caching Results383384```bash385#!/bin/bash386387CACHE_DIR=".shellcheck_cache"388mkdir -p "$CACHE_DIR"389390check_script() {391 local script="$1"392 local hash393 local cache_file394395 hash=$(sha256sum "$script" | cut -d' ' -f1)396 cache_file="$CACHE_DIR/$hash"397398 if [[ ! -f "$cache_file" ]]; then399 if shellcheck "$script" > "$cache_file" 2>&1; then400 touch "$cache_file.ok"401 else402 return 1403 fi404 fi405406 [[ -f "$cache_file.ok" ]]407}408409find . -name "*.sh" | while read -r script; do410 check_script "$script" || exit 1411done412```413414## Output Formats415416### Default Format417418```bash419shellcheck script.sh420421# Output:422# script.sh:1:3: warning: foo is referenced but not assigned. [SC2154]423```424425### GCC Format (for CI/CD)426427```bash428shellcheck --format=gcc script.sh429430# Output:431# script.sh:1:3: warning: foo is referenced but not assigned.432```433434### JSON Format (for parsing)435436```bash437shellcheck --format=json script.sh438439# Output:440# [{"file": "script.sh", "line": 1, "column": 3, "level": "warning", "code": 2154, "message": "..."}]441```442443### Quiet Format444445```bash446shellcheck --format=quiet script.sh447448# Returns non-zero if issues found, no output otherwise449```450451## Best Practices4524531. **Run ShellCheck in CI/CD** - Catch issues before merging4542. **Configure for your target shell** - Don't analyze bash as sh4553. **Document exclusions** - Explain why violations are suppressed4564. **Address violations** - Don't just disable warnings4575. **Enable strict mode** - Use `--enable=all` with careful exclusions4586. **Update regularly** - Keep ShellCheck current for new checks4597. **Use pre-commit hooks** - Catch issues locally before pushing4608. **Integrate with editors** - Get real-time feedback during development461462## Resources463464- **ShellCheck GitHub**: https://github.com/koalaman/shellcheck465- **ShellCheck Wiki**: https://www.shellcheck.net/wiki/466- **Error Code Reference**: https://www.shellcheck.net/467
Full transparency — inspect the skill content before installing.