check-script - evaluates the quality and security of shell and Python scripts
check-script [OPTIONS] SCRIPT|FOLDER|-…
check-script explain [--lang fr|en] [--config FILE] RULE…
check-script init [OPTIONS] [FOLDER]
check-script diff [OPTIONS] BEFORE.json AFTER.json
check-script lsp [--lang fr|en]
check-script scores shell or Python 3 scripts over five categories (Security, Robustness, Maintainability, Portability, Performance), each out of 10, with the number of issues by severity (Critical, High, Medium, Low), an overall score and a grade from A to E.
It makes use of shellcheck(1), shfmt(1), bashate(1), checkbashisms(1), ruff(1), bandit(1), semgrep(1), mypy(1), radon(1), vermin(1), gitleaks(1), trufflehog(1) and bash -n for shell; ruff(1), bandit(1), semgrep(1), mypy(1), radon(1), vermin(1) (and, on request, pylint(1), pyright(1)) for Python, when they are installed; it complements them with built-in rules (see --list-rules).
A script is treated as Python if its shebang names python or, without a shebang, if its extension is .py or .pyw.
A FOLDER is scanned at its own level, or with all its sub-folders with --recursive (.sh, .bash, .ksh, .dash, .zsh, .py, .pyw files and extensionless files whose shebang names a shell or Python; hidden folders, venv, site-packages, pycache and node_modules are excluded). A PATTERN ('.sh', *'src/.py', *'*/.sh') is expanded by check-script itself; without a slash it applies to the current folder, or to the whole tree with --recursive. - reads the script from standard input.
- -o, --output FILE
-
Writes the report to FILE; format chosen by extension (.md, .adoc, .html, .json, .sarif, .codeclimate.json, .txt). Repeatable.
- -f, --format FORMAT
-
terminal, md, adoc, html, pdf, json, sarif, codeclimate (GitLab Code Quality), junit (JUnit XML) or github (GitHub Actions annotations): format of the standard output, and of -o files with no recognized extension (the extension takes precedence).
- -w, --watch
-
Re-analyzes each script when it is saved (the modified scripts, or all targets if -o files are written); Ctrl+C to stop.
- -l, --lang fr|en
-
Report language (default: LC_ALL, LC_MESSAGES then LANG).
- -s, --shell DIALECT
-
Forces the dialect (sh, bash, dash, ksh, zsh, python).
- --python-target VERSION
-
Minimum Python version the scripts must support (default: 3.9): passed to vermin, ruff, pylint and pyright.
- -p, --profile strict|default|legacy
-
Scoring and threshold profile.
- --context root|cron|systemd|interactive
-
Execution context: enables dedicated rules and raises some severities. Repeatable.
- --follow-source
-
Follows sourced files (shellcheck -x).
- -c, --config FILE
-
YAML configuration (default: ./.checkscript.yaml then ~/.config/check-script/config.yaml).
- --with TOOL
-
Enables a tool that is disabled by default (pylint, pyright). Repeatable or comma-separated.
- --without TOOL
-
Disables a tool: shellcheck, shfmt, bashate, checkbashisms, gitleaks, trufflehog, syntax, ruff, bandit, semgrep, mypy, pyright, pylint, radon, vermin, pydeps, pip-audit, hadolint, actionlint, zizmor, commands, custom or builtin. Repeatable or comma-separated.
- --no-external
-
Uses only the built-in rules.
- --ref REFERENCE
-
Shows only the issues attached to this reference (CWE, OWASP, ANSSI; start of the name, case-insensitive). Repeatable.
- --no-embedded
-
In a folder, does not analyze embedded scripts (GitHub Actions, GitLab CI, Dockerfile, Makefile, Ansible).
- --dashboard FILE.html
-
Team dashboard (one repository per target folder, trends).
- --history-dir FOLDER
-
Stores the history of analyzed folders in FOLDER.
- -r, --recursive
-
Walks the sub-folders of the given folders (by default only the scripts of the folder itself are analysed).
- --exclude PATTERN
-
Excludes from a folder analysis the paths matching the pattern (.gitignore syntax: vendor/, *.min.sh, /gen/); repeatable. Adds to the exclude key of the configuration and to the .checkscriptignore file at the root of the folder.
- --changed-since REF
-
Analyzes only the scripts modified since the git reference REF.
- --no-cache
-
Re-analyzes everything, without reusing the reports of unchanged scripts (~/.cache/check-script/results).
- --explain
-
Terminal: cost of each rule on the score, and gain from fixing it.
- --sort category|impact
-
Terminal: issues by category, or by quick gain.
- -j, --jobs N
-
Scripts of a folder analyzed concurrently (default: depends on the number of processors; 1: one after the other).
- -b, --baseline REPORT.json
-
Baseline JSON report: only new issues are detailed and the evolution of the scores is shown.
- --baseline-update
-
With --baseline: rewrites the baseline without the fixed issues (a script with new issues keeps its entry).
- -i, --interactive
-
With --fix: offers each fix one at a time (y/n/a/q).
- --fail-on-new SEVERITY
-
With --baseline: exit code 1 if a new issue reaches this severity.
- --fix
-
Fixes safe defects in the file (ShellCheck fixes, built-in fixes, shfmt formatting). Aborts if the syntax would become invalid.
- --dry-run
-
With --fix: prints the unified diff without modifying the file.
- --backup
-
With --fix: keeps the original as FILE*.orig*.
- --details, --summary
-
Terminal: all issues with their fix / summary only.
- --no-source
-
Terminal: does not print the line of code (and the column marker) under each issue.
- --color, --no-color
-
Forces or disables color (default: automatic; NO_COLOR is honored).
- -q, --quiet
-
No report on standard output.
- --fail-under SCORE|CATEGORY=SCORE
-
Exit code 1 if the overall score, or that of a category, is below the threshold. Separator ,; decimals with a dot.
- --list-tools, --list-rules
-
Detected tools / built-in rules.
- --all
-
With --list-rules: also the tool codes classified by check-script.
- -v, --version, -h, --help
-
Version / help.
In the script:
# check-script disable=RULE[,RULE...] (current line, or next one if comment only)
# check-script disable-next-line=RULE[,...]
# check-script disable-file=RULE[,...]Wildcards: SC20\*, all.
- 0
-
Analysis performed.
- 1
-
Threshold not met (--fail-under, --fail-on-new).
- 2
-
Usage or configuration error.
- 3
-
Script not found or unreadable, report cannot be written.
check-script explain RULE… describes a rule: category, severity, tool, CWE / OWASP / ANSSI references, an avoid / write instead example, equivalent codes in other tools, and the ways to ignore it (directive, rules.disabled). RULE is an identifier such as SEC003, SC2086, B602 or a custom rule of the configuration (--config); see --list-rules --all. Unknown identifier: exit code 2 with suggestions.
check-script diff [-f text|md|json] [--summary] [--fail-on-new SEVERITY] [--fail-on-worse] BEFORE.json AFTER.json compares two JSON reports: new, fixed and unchanged issues per script (matched by fingerprint, independent of the line number), score evolution, added and removed scripts. --fail-on-new exits with code 1 if a new issue reaches the severity, --fail-on-worse if the score of a script dropped.
check-script init [FOLDER] writes FOLDER/.checkscript.yaml (default: the current folder) with a profile suggested by the analysis of the scripts it contains (average score ≥ 8.5: strict; < 6: legacy; otherwise default), the requested contexts and exclusions, and commented examples (rules, tools, Python target). Options: --profile (forces the profile, no analysis), --context (repeatable), --exclude (repeatable), --baseline FILE.json (also writes the baseline report, to use with --baseline), --no-analysis, --no-external, --force (replaces an existing file), --stdout, --lang. An existing file is never replaced without --force.
check-script lsp is an LSP (Language Server Protocol) server on standard input and output, for editors (VS Code extension, Eclipse plugin, Geany LSP plugin, Neovim…): diagnostics (full analysis on open and on save, built-in rules while typing), quick fixes, hover, formatting (shfmt, ruff format). Initialization options: lang, profile, analyzeOnType, typingDelay.
check-script deploy.sh
check-script --profile strict --context root -o report.html deploy.sh
check-script --fix --dry-run scripts/
check-script -q --fail-under 7 --fail-under security=8 -o r.sarif scripts/
check-script -b old.json --fail-on-new high scripts/- .checkscript.yaml (script folder, then parents up to the git root), ~/.config/check-script/config.yaml
-
Configuration (example: /usr/share/doc/check-script/checkscript.example.yaml).