ShellCheck: a static analyser for bash and sh scripts
ShellCheck, a static analysis tool for shell scripts. From your terminal Run shellcheck yourscript in your terminal for instant output, as seen above.
At a glance
- What is it?
- ShellCheck reads a shell script without running it and reports quoting bugs, misused commands and portability traps. It is a GPL-3.0 Haskell program, and the last push to the repository was on 2025-08-04.
- Who is it for?
- Adopt ShellCheck if you maintain shell scripts that run in CI, on other people's machines, or under a shell you did not write them for; its exit codes make it a drop-in build step, and the README's own advice is to pin a specific version so a new release's warnings do not break the build. Skip it if your scripts are one-off interactive commands, since the warnings target code that has to survive future circumstances.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The beginner mistakes and the advanced corner cases
ShellCheck exists because the shell is permissive in ways that hurt later. The README states three goals: clarify beginner's syntax issues that produce cryptic errors, clarify intermediate semantic problems that make a shell behave counter-intuitively, and flag subtle caveats and pitfalls that make an advanced user's working script fail under future circumstances. Those are three different audiences, and the third is the one that justifies a tool rather than a style guide. A script that works today because no word in a variable contains a space is not correct; it is lucky, and ShellCheck is aimed at the gap between the two.
The intended user is anyone who writes or inherits shell scripts and wants the failure to happen at review time rather than at 3 a.m. The README's gallery of bad code is organised by category: quoting, conditionals, frequently misused commands, common beginner's mistakes, style, data and typing errors, robustness, portability, and miscellaneous. That taxonomy is a fair description of the tool's scope. It does not check whether your script does the right thing, only whether it does a thing the shell will interpret the way you probably meant.
Parsing without executing, and the exit code contract
The mechanism is static: ShellCheck reads the script as text and never runs it, which is why it can be pointed at a file whose side effects you would not want. The repository is written in Haskell, with the source under src/ and the build described by ShellCheck.cabal and stack.yaml. The man page lives in shellcheck.1.md, so the command-line surface is documented separately from the README.
Integration rests on exit codes. The README says the tool "makes canonical use of exit codes, so you can just add a shellcheck command as part of the process." In practice that means a non-zero exit when warnings are present, which is what lets a Makefile target or a CI step fail the build without any wrapper script. Output formats are selectable: the README lists simple JSON, CheckStyle-compatible XML, GCC-compatible warnings, and human-readable text with or without ANSI colours, with further documentation on the Integration wiki page. The GCC format is what most editors consume, which is why the README can claim support for "most other editors" through it rather than through a dedicated plugin.
One design consequence worth naming: because analysis is syntactic and semantic rather than execution-based, ShellCheck cannot know the values your variables will hold at runtime. Findings are therefore phrased as warnings and suggestions, and some of them will be wrong about your intent. That is the price of not running the script.
Installing ShellCheck and running it on a first script
The README calls the package manager the easiest route. On Debian-based distributions the command is a single apt install, and the binary lands on your PATH as shellcheck.
sudo apt install shellcheckOn macOS with Homebrew the equivalent is brew install shellcheck, and the README also lists MacPorts as sudo port install shellcheck. Windows users have three documented options: choco install shellcheck, winget install --id koalaman.shellcheck, and scoop install shellcheck.
Once installed, the first real use is the one the README shows: pass a script path as an argument.
shellcheck yourscriptThe output is a list of findings, each carrying an SC-prefixed code, a line and column, and an explanation. To see the same analysis inside a pipeline without installing anything, the README documents the official image, which mounts the current directory at /mnt.
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck:stable myscriptThe README notes that :stable, a specific tag such as :v0.4.7, and :latest for daily builds are all available, and that koalaman/shellcheck-alpine is an alternative if you want a larger Alpine-based image. From conda-forge, conda install -c conda-forge shellcheck is also listed. If you build from source, the README gives cabal install ShellCheck (installing to ~/.cabal/bin) and stack install ShellCheck (installing to ~/.local/bin), with a separate test step described in the repository.
Putting it in a build, and pinning the version you get
The README's Makefile example is a target that fails when any file matches the glob. The comment in the example states the intent plainly: fail if any of these files have warnings.
check-scripts:
# Fail if any of these files have warnings
shellcheck myscripts/*.shThe same command works as a CI step. The README shows a Travis CI .travis.yml entry with the identical comment and command, and lists Travis CI, Codacy, Code Climate, Code Factor, Codety, CircleCI (via the ShellCheck Orb), GitHub Actions on Linux only, Trunk Code Quality, and CodeRabbit as services that either ship ShellCheck or integrate it. GitLab is named as an example of a service where you install it yourself through the package manager or a binary release.
The README then gives advice that is easy to skim past: it is a good idea to manually install a specific ShellCheck version regardless, to avoid surprise build breaks when a new version with new warnings is published. That is a real operational constraint, not boilerplate. A linter that gains checks between releases will turn a green pipeline red without anyone touching the scripts, and the fix is version pinning rather than disabling checks. The Trunk plugin is cited as one integration that lets you explicitly version the ShellCheck install.
Suppressing findings, and when the tool is the wrong choice
ShellCheck will produce findings you disagree with, and the README devotes a section to ignoring issues. The mechanism is a directive comment carrying the rule code, which is why the search phrase for disabling a specific rule names SC2086 directly. Suppression is per-rule and per-line, so it is a scalpel rather than a global off switch, but it also means every suppression is a small piece of evidence that someone reviewed the finding and decided against it.
The wrong-tool cases are worth stating. First, ShellCheck analyses shell scripts; it is not a general-purpose script linter, and a Python or Perl file passed to it is outside its remit. Second, the README frames the goals around scripts that must keep working, so a throwaway command you paste into a terminal once gains little from being linted. Third, and most importantly, a clean ShellCheck run is not a correctness proof. The tool cannot see the values your variables will hold, so a script can pass with no findings and still delete the wrong directory. Treat a clean run as the absence of a known class of mistakes, not as validation of intent. Fourth, the README's own warning about new releases means an unpinned install is a moving target; if your pipeline cannot tolerate that, pin or do not adopt.
How ShellCheck differs from a formatter such as shfmt
The obvious adjacent tool is shfmt, which formats shell source: it rewrites indentation, spacing and line breaks to a canonical style. The difference in approach is the point. shfmt changes the bytes of your script and leaves semantics alone; ShellCheck changes nothing and reports on semantics. Running shfmt on a script with an unquoted variable expansion produces tidier unquoted expansion. Running ShellCheck on it produces a finding about the unquoted expansion. They are complementary, and a repository can reasonably run both, but neither substitutes for the other.
A second comparison is with the shell's own checking. bash -n parses a script and reports syntax errors without executing it, which overlaps with ShellCheck's first goal but stops there: it has nothing to say about quoting, misused commands, portability or the pitfalls in the README's later categories. If your only concern is whether the file parses, bash -n is already installed. If your concern is whether it will behave, that is the layer ShellCheck adds.
Licence, maintenance and what an upgrade actually costs
ShellCheck is GPL-3.0, as stated in the README and confirmed by the LICENSE file at the repository root. For most users this is unremarkable: you are running a command-line tool, not linking a library into your product. The distinction matters if you intend to embed or redistribute it, and that is a question for your own legal review rather than something this article can settle. The licence identifier is the fact; the implications depend on your distribution model.
The repository is not archived. Its last push was on 2025-08-04, which is the same date as the v0.11.0 release. The release cadence visible in the tags is uneven: v0.9.0 in December 2022, v0.10.0 in March 2024, v0.11.0 in August 2025. That spacing is the honest signal about upgrade cost. Because new releases can add warnings, the cost of upgrading is not the download but the review of every new finding across your scripts. The README's recommendation to install a specific version is the mitigation, and it converts an unpredictable cost into a scheduled one.
Editorial conclusion
Adopt ShellCheck if you maintain shell scripts that run in CI, on other people's machines, or under a shell you did not write them for; its exit codes make it a drop-in build step, and the README's own advice is to pin a specific version so a new release's warnings do not break the build. Skip it if your scripts are one-off interactive commands, since the warnings target code that has to survive future circumstances. Before rolling it out across a repository, run it on the oldest and most portability-sensitive script you own and check how many SC-prefixed findings you get, because the fix volume, not the install, is the real cost.
Frequently asked questions
What is ShellCheck?
ShellCheck is a GPL-3.0 static analysis tool that gives warnings and suggestions for bash and sh shell scripts. The README describes three goals: clarifying beginner's syntax issues, intermediate semantic problems, and subtle pitfalls that could make an advanced user's script fail later.
How do I use ShellCheck?
The README's terminal example is shellcheck yourscript, which produces instant output. You can also paste a script at shellcheck.net, which the README says is always synchronised to the latest git commit, or wire the command into a build or test suite.
Is ShellCheck a linter?
Yes. It reads a script without executing it and reports findings with SC-prefixed codes, line and column positions, and explanations. The README lists JSON, CheckStyle XML, GCC-compatible warnings and human-readable text as output formats.
How do I install ShellCheck on Ubuntu?
The README gives sudo apt install shellcheck for Debian-based distributions. Cabal, Stack, conda-forge, Snap, Docker Hub and pre-compiled binary releases are the other documented routes.
How do I install ShellCheck on Windows?
The README lists three package managers: choco install shellcheck, winget install --id koalaman.shellcheck, and scoop install shellcheck. GitHub Actions integration is documented as Linux only.
How do I use ShellCheck in VSCode?
The README names vscode-shellcheck as the VSCode extension, alongside ALE, Neomake and Syntastic for Vim, Flycheck and Flymake for Emacs, SublimeLinter for Sublime, and linter-shellcheck-pulsar for Pulsar Edit.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/koalaman-shellcheck)
Community notes