About ShellCheck

ShellCheck is a static analysis and linting tool for sh/bash scripts. It's mainly focused on handling typical beginner and intermediate level syntax errors and pitfalls where the shell just gives a cryptic error message or strange behavior, but it also reports on a few more advanced issues where corner cases can cause delayed failures.

Haskell source code is available on GitHub!

Run ShellCheck online

Go to ShellCheck.net to copy-paste a shell script and get immediate, automatic feedback!

The online version is always synced against the latest git commit.

Run ShellCheck locally

If you download and compile the source code, you get a pretty terminal frontend!

With cabal installed, you can also install the latest stable release with cabal install shellcheck



Run ShellCheck in your editor

ShellCheck can output gcc style error messages and checkstyle compatible xml, which allows any editor to show inlined error messages.

It's also supported directly by Syntastic in Vim and Flycheck in Emacs.




What does ShellCheck check?

Here is an incomplete list of things ShellCheck warns about and suggests improvements to:

Unquoted globs for find/grep
find . -name *.ogg
Constant test expressions
[[ n != 0 ]]
Redirecting into source file
sed -e 's/foo/bar/g' file > file
Globs in regex context
grep '*foo*' file
PS1 colors not in \[..\]
PS1='\e[0;32m\$\e[0m '
Prematurely terminated find -exec
find / -exec touch {} && echo {} \;
Literal quotes in arguments
verbose='--verbose="true"'
cmd $verbose
Assignment in subshells
echo foo | read bar
echo $bar
Confusing time(1) for builtin
time --format=%s sleep 10
~ in quotes
rm "~/my file.txt"
Single, quoted 'for' argument
for f in "*.ogg"
do rm $f; done
Arithmetic truncation
echo $((n/180*100))
Functions used externally
f() { rm file; }; sudo f
Unused variables
var=World; echo "Hello " var
Looping over ls output
for f in $(ls *.ogg)
do ...; done
Unquoted command expansion
tar cf file$(date).tar dir
Unquoted $@
touch $@
Unicode quotes
rm “file”
Attempted redirection of stdout+stderr
cmd 2>&1 > /dev/null
Attempted indirect assignment
var$n="Hello"
Attempted indirect reference
echo ${var$n}
Variables in single quotes
echo 'Path is $PATH'
Comparing numbers with < or >
[[ $n > 0 ]]
Unsupported [ ] operators
[ foo =~ re ]
Quoted =~ regex
[[ $foo =~ "fo+" ]]
Tautology due to spacing
[[ $foo==0 ]]
Variable brace expansion (Bash)
echo {1..$n}
Commands eating loop input
while read host; do ssh "$host" uptime; done < file
Decimals arithmetics
echo $((3.14*r*r))
Comma separated arrays
var=(1, 2, 3)
Misused 'exec'
exec foo; echo "Done!"
Globs that could become options
touch ./-l; ls *
Variables in printf format
printf "Hello $name"
Prefix assignments in args
var=42 echo $var
Useless use of echo
echo $(date)
Redirecting sudo
sudo echo 'alias sl=ls' >> /etc/profile
[] around ranges in tr
tr '[a-z]' '[A-Z]'
Misquoted traps
trap "echo \"Runtime: ${SECONDS}s\"" exit
&& in [ .. ]
[ $n && $m ]
Singlequote closed by apostrophe
echo 'Don't forget to run foo --update!'
Attempting to escape ' in ''
var='Don\'t try this at home'
Misused char class globs
ls *[:digit:].txt
Positional parameter misreference
echo "Argument 10 is $10"
cd-and-back antipattern
for d in *; do cd "$d"; cmd; cd ..; done
Missing semicolons in loops
for f in *.mp3 do true; done
$ in assignments
$foo=42
Spaces in assignment
var = 42
Features shebang may not support
#!/bin/sh
echo {1..10}
Spurious $()/``
cmd='echo foo'; `$cmd`;


More fun stuff

For more fun stuff, see the author's home page!.