ShellCheck: A static analysis tool for shell scripts

Build Status

ShellCheck is a GPLv3 tool that presents warnings and suggestions for bash/sh shell scripts:

Screenshot of a terminal showing problematic shell script lines highlighted

The targets of ShellCheck are

  • To present and clarify conventional beginner’s syntax points that trigger a shell
    to present cryptic error messages.

  • To present and clarify conventional intermediate level semantic problems that
    trigger a shell to behave strangely and counter-intuitively.

  • To present subtle caveats, corner cases and pitfalls that will trigger an
    developed user’s in another case working script to fail below future conditions.

Uncover the gallery of unhealthy code for examples of what ShellCheck can encourage you resolve!

Table of Contents

  • spend
    • On the receive
    • From your terminal
    • In your editor
    • In your fabricate or test suites
  • Installing
  • Compiling from source
    • Installing Cabal
    • Compiling ShellCheck
    • Operating assessments
  • Gallery of unhealthy code
    • Quoting
    • Conditionals
    • Recurrently misused instructions
    • Celebrated beginner’s errors
    • Model
    • Info and typing errors
    • Robustness
    • Portability
    • Miscellaneous
  • Testimonials
  • Ignoring points
  • Reporting bugs
  • Contributing
  • Copyright
  • Other Resources


There are a preference of systems to make spend of ShellCheck!

On the receive

Paste a shell script on https://www.shellcheck.receive for instantaneous suggestions.

ShellCheck.receive is repeatedly synchronized to the most modern git commit, and is the top doubtless manner to present ShellCheck a drag. State your mates!

From your terminal

Urge shellcheck yourscript for your terminal for instantaneous output, as considered above.

In your editor

You furthermore mght can survey ShellCheck suggestions without prolong in a big selection of editors.

  • Vim, thru ALE, Neomake, or Syntastic:

Screenshot of Vim showing inlined shellcheck feedback.

  • Emacs, thru Flycheck or Flymake:

Screenshot of emacs showing inlined shellcheck feedback.

  • Neat, thru SublimeLinter.

  • Atom, thru Linter.

  • VSCode, thru vscode-shellcheck.

  • Most other editors, thru GCC error compatibility.

In your fabricate or test suites

Whereas ShellCheck is mostly supposed for interactive spend, it will without problems be added to builds or test suites.
It makes canonical spend of exit codes, so it’s essential probably correct add a shellcheck uncover as segment of the technique.

As an example, in a Makefile:

    # Fail if any of these files beget warnings
    shellcheck myscripts/*.sh

or in a Travis CI .travis.yml file:

  # Fail if any of these files beget warnings
  - shellcheck myscripts/*.sh

Products and services and platforms that beget ShellCheck pre-put in and in a self-discipline to make spend of:

  • Travis CI
  • Codacy
  • Code Climate
  • Code Ingredient
  • CircleCI by strategy of the ShellCheck Orb
  • Github (supreme Linux)

Products and services and platforms with third occasion plugins:

  • SonarQube thru sonar-shellcheck-plugin

Most other services and products, in conjunction with GitLab, let you set up
ShellCheck yourself, both thru the machine’s kit manager (survey Installing),
or by downloading and unpacking a binary originate.

It be a staunch recommendation to manually set up a particular ShellCheck model regardless. This avoids
any surprise fabricate breaks when a brand unique model with unique warnings is revealed.

For custom-made filtering or reporting, ShellCheck can output easy JSON, CheckStyle fancy minded XML,
GCC fancy minded warnings as successfully as human readable textual impart material (with or without ANSI colors). Uncover the
Integration wiki net page for additional documentation.


The finest manner to set up ShellCheck regionally is thru your kit manager.

On programs with Cabal (installs to ~/.cabal/bin):

cabal update
cabal set up ShellCheck

On programs with Stack (installs to ~/.native/bin):

stack update
stack set up ShellCheck

On Debian primarily based entirely distros:

true-gather set up shellcheck

On Arch Linux primarily based entirely distros:

pacman -S shellcheck

or gather the dependency free shellcheck-bin from the AUR.

On Gentoo primarily based entirely distros:

emerge --question shellcheck

On EPEL primarily based entirely distros:

yum -y set up epel-originate
yum set up ShellCheck

On Fedora primarily based entirely distros:

dnf set up ShellCheck

On FreeBSD:

pkg set up hs-ShellCheck

On macOS (OS X) with Homebrew:

brew set up shellcheck

Or with MacPorts:

sudo port set up shellcheck

On OpenBSD:

pkg_add shellcheck

On openSUSE

zypper in ShellCheck

Or spend OneClickInstall –

On Solus:

eopkg set up shellcheck

On Windows (by strategy of chocolatey):

C:> choco set up shellcheck

Or Windows (by strategy of scoop):

C:> scoop set up shellcheck

From conda-forge:

conda set up -c conda-forge shellcheck

From Snap Store:

snap set up --channel=edge shellcheck

From Docker Hub:

docker trip --rm -v "$PWD:/mnt" koalaman/shellcheck:stable myscript
# Or :v0.4.7 for that model, or :most modern for daily builds

or spend koalaman/shellcheck-alpine in expose for you the next Alpine Linux primarily based entirely image to elongate. It if truth be told works precisely fancy a typical Alpine image, however has shellcheck preinstalled.

The usage of the nix kit manager:

nix-env -iA nixpkgs.shellcheck

Alternatively, it’s essential probably gather pre-compiled binaries for the most modern originate here:

  • Linux, x86_64 (statically linked)
  • Linux, armv6hf, i.e. Raspberry Pi (statically linked)
  • Linux, aarch64 aka ARM64 (statically linked)
  • macOS, x86_64
  • Windows, x86

or survey the GitHub Releases for other releases
(in conjunction with the most modern meta-originate for daily git builds).

Distro applications already reach with a man net page. Ought to you furthermore mght can very successfully be constructing from source, it will also also be put in with:

pandoc -s -f markdown-orderly -t man -o shellcheck.1
sudo mv shellcheck.1 /usr/portion/man/man1

Travis CI

Travis CI has now integrated ShellCheck by default, so you plot now no longer need to manually set up it.

Ought to you proceed to desire to attain so in expose to upgrade at your leisure or guarantee you furthermore mght can very successfully be
the spend of the most modern originate, practice the steps below to set up a binary model.

Installing a pre-compiled binary

The pre-compiled binaries reach in tar.xz files. To decompress them, be definite
xz is put in.
On Debian/Ubuntu/Mint, it’s essential probably true set up xz-utils.
On Redhat/Fedora/CentOS, yum -y set up xz.

A straightforward installer can also attain one thing fancy:

scversion="stable" # or "v0.4.7", or "most modern"
wget -qO- "${scversion?}/shellcheck-${scversion?}.linux.x86_64.tar.xz" | tar -xJv
cp "shellcheck-${scversion}/shellcheck" /usr/bin/
shellcheck --model

Compiling from source

This part describes systems to manufacture ShellCheck from a source directory. ShellCheck is written in Haskell and requires 2GB of RAM to bring together.

Installing Cabal

ShellCheck is built and packaged the spend of Cabal. Set up the kit cabal-set up from your machine’s kit manager (with e.g. true-gather, brew, emerge, yum, or zypper).

On macOS (OS X), it’s essential probably attain a rapid set up of Cabal the spend of brew, which takes a rapid while rather then better than 30 minutes when you happen to are attempting and produce together it from source.

$ brew set up cabal-set up

On MacPorts, the kit is as a replace known as hs-cabal-set up, whereas native Windows users must always set up the most modern model of the Haskell platform from

Verify that cabal is put in and update its dependency listing with

$ cabal update

Compiling ShellCheck

git clone this repository, and cd to the ShellCheck source directory to manufacture/set up:

$ cabal set up

Or when you happen to imply to trip the assessments:

$ cabal set up --enable-assessments

This will bring together ShellCheck and set up it to your ~/.cabal/bin directory.

Add this directory to your PATH (for bash, add this to your ~/.bashrc):

export PATH="$HOME/.cabal/bin: $PATH"

Log out and in again, and test that your PATH is decided up accurately:

$ which shellcheck

On native Windows, the PATH must always already be location up, however the machine
can also spend a legacy codepage. In cmd.exe, powershell.exe and Powershell ISE,
be definite to make spend of a TrueType font, now no longer a Raster font, and location the energetic
codepage to UTF-8 (65001) with chcp:

In Powershell ISE, you furthermore mght can need to additionally update the output encoding:

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

Operating assessments

To trip the unit test suite:

$ cabal test

Gallery of unhealthy code

So what extra or less issues does ShellCheck inquire of? Here is an incomplete listing of detected points.


ShellCheck can acknowledge loads of kinds of incorrect quoting:

echo $1                           # Unquoted variables
salvage . -establish *.ogg                # Unquoted salvage/grep patterns
rm "~/my file.txt"                # Quoted tilde expansion
v='--verbose="correct"'; cmd $v      # Literal quotes in variables
for f in "*.ogg"                  # Incorrectly quoted 'for' loops
touch $@                          # Unquoted $@
echo 'Don't neglect to restart!'   # Singlequote closed by apostrophe
echo 'Don't are attempting this at home'    # Attempting to flee ' in ''
echo 'Course is $PATH'              # Variables in single quotes
entice "echo Took ${SECONDS}s" 0    # In advance expanded entice


ShellCheck can acknowledge many kinds of incorrect test statements.

[[ n != 0 ]]                      # Fixed test expressions
[[ -e *.mpg ]]                    # Existence assessments of globs
[[ $foo==0 ]]                     # Steadily correct due to lacking spaces
[[ -n "$foo " ]]                  # Steadily correct due to literals
[[ $foo =~ "fo+" ]]               # Quoted regex in=~
[ foo =~ re ]                     # Unsupported [ ] operators
[ $1 -eq "shellcheck" ]           # Numerical comparison of strings
[ $n && $m ]                      # && in [ .. ]
[ grep -q foo file ]              # Recount without $(..)
[[ "$$file" == *.jpg ]]           # Comparisons that will per chance probably't succeed
(( 1 -lt 2 ))                     # The usage of test operators in ((..))

Recurrently misused instructions

ShellCheck can acknowledge conditions the place instructions are aged incorrectly:

grep '*foo*' file                 # Globs in regex contexts
salvage . -exec foo {} && bar {} ;  # In advance terminated salvage -exec
sudo echo 'Var=42' > /etc/profile # Redirecting sudo
time --format=%s sleep 10         # Passing time(1) flags to time builtin
whereas be taught h; attain ssh "$h" uptime  # Instructions piquant whereas loop input
alias archive='mv $1 /backup'     # Defining aliases with arguments
tr -cd '[a-zA-Z0-9]'              # [] spherical ranges in tr
exec foo; echo "Finished!"            # Misused 'exec'
salvage -establish *.bak -o -establish *~ -delete  # Implicit precedence in salvage
# salvage . -exec foo> bar ;       # Redirections in salvage
f() { whoami; }; sudo f           # Exterior spend of interior capabilities

Celebrated beginner’s errors

ShellCheck acknowledges many overall beginner’s syntax errors:

var=42                          # Spaces spherical=in assignments
$foo=42                           # $ in assignments
for $var in *; attain ...             # $ in for loop variables
var$n="Hi there"                     # Injurious indirect assignment
echo ${var$n}                     # Injurious indirect reference
var=(1, 2, 3)                     # Comma separated arrays
array=( [index]=worth )         # Wrong index initialization
echo $var[14]                     # Missing {} in array references
echo "Argument 10 is $10"         # Positional parameter misreference
if $(myfunction); then ..; fi     # Wrapping instructions in $()
else if othercondition; then ..   # The usage of 'else if'
f; f() { echo "hi there world; }     # The usage of feature sooner than definition
[ false ]                         # 'spurious' being correct
if ( -f file )                    # The usage of (..) rather then test


ShellCheck can gather suggestions to make stronger style:

[[ -z $(find /tmp | grep mpg) ]]  # Employ grep -q as a replace
a >> log; b >> log; c >> log      # Employ a redirection block as a replace
echo "The time is `date`"         # Employ $() as a replace
cd dir; direction of *; cd ..;         # Employ subshells as a replace
echo $[1+2]                       # Employ favorite $((..)) rather then former $[]
echo $(($RANDOM % 6))             # Create now no longer spend $ on variables in $((..))
echo "$(date)"                    # Useless spend of echo
cat file | grep foo               # Useless spend of cat

Info and typing errors

ShellCheck can acknowledge points linked to recordsdata and typing:

args="$@"                         # Assigning arrays to strings
files=(foo bar); echo "$files"    # Referencing arrays as strings
reveal -A arr=(foo bar)          # Associative arrays without index
printf "%sn" "Arguments: $@."    # Concatenating strings and arrays
[[ $# > 2 ]]                      # Evaluating numbers as strings
var=World; echo "Hi there " var      # Unused lowercase variables
echo "Hi there $establish"                # Unassigned lowercase variables
cmd | be taught bar; echo $bar         # Assignments in subshells
cat foo | cp bar                  # Piping to instructions that plot now no longer be taught
printf '%s: %sn' foo             # Mismatches in printf argument rely


ShellCheck can gather suggestions for making improvements to the robustness of a script:

rm -rf "$STEAMROOT/"*            # Catastrophic rm
touch ./-l; ls *                 # Globs that will per chance probably well become alternate choices
salvage . -exec sh -c 'a && b {}' ; # Rep -exec shell injection
printf "Hi there $establish"             # Variables in printf format
for f in $(ls *.txt); attain         # Iterating over ls output
export MYVAR=$(cmd)              # Masked exit codes
case $model in 2.*) : ;; 2.6.*) # Shadowed case branches


ShellCheck will warn when the spend of capabilities now no longer supported by the shebang. As an example, when you happen to location the shebang to #!/bin/sh, ShellCheck will warn about portability points a lot like checkbashisms:

echo {1..$n}                     # Works in ksh, however now no longer bash/flee/sh
echo {1..10}                     # Works in ksh and bash, however now no longer flee/sh
echo -n 42                       # Works in ksh, bash and flee, undefined in sh
entice 'exit 42' sigint            # Unportable signal spec
cmd &> file                      # Unportable redirection operator
be taught foo  /dev/tcp/host/22      # Unportable intercepted files
foo-bar() { ..; }                # Undefined/unsupported function name
[ $UID = 0 ]                     # Variable undefined in dash/sh
local var=value                  # local is undefined in sh
time sleep 1 | sleep 5           # Undefined uses of 'time'


ShellCheck recognizes a menagerie of other issues:

PS1='e[0;32m$e[0m '            # PS1 colors not in [..]
PATH="$PATH:~/bin"                # Literal tilde in $PATH
rm “file”                         # Unicode quotes
echo "Hello world"                # Carriage return / DOS line endings
echo hello                       # Trailing spaces after 
var=42 echo $var                  # Expansion of inlined environment
#!/bin/bash -x -e                 # Common shebang errors
echo $((n/180*100))               # Unnecessary loss of precision
ls *[:digit:].txt                 # Bad character class globs
sed 's/foo/bar/' file > file      # Redirecting to input
whereas getopts "a" f; attain case $f in "b") # Unhandled getopts flags


First and primary you furthermore mght can very successfully be fancy “shellcheck is righteous” however then you definately can also very successfully be fancy “wtf are we level-headed the spend of bash”

Alexander Tarasikov,
by strategy of Twitter

Ignoring points

Factors can also also be missed by strategy of environmental variable, uncover line, individually or globally within a file:

Reporting bugs

Please spend the GitHub iss

Read More

Recent Content