ShellCheck is a static analysis tool for shell scripts. One can use it to finds bugs in your shell scripts. It is written in Haskell. You can find warnings and suggestions for bash/sh shell scripts with this tool. Let us see how to install and use ShellCheck on a Linux or Unix-like system to enhance your shell scripts, avoid errors and productivity.

Shell scripting is fun. It is useful to create nice (perhaps ugly) things in shell scripting. Shell scripts are useful for automating processes that you repeat at the prompt.
how to lint your bash sh zsh shell scripts on linux unix macos

ShellCheck lint script analysis tool

The quality of the shell script can be dangerous. Most new users, sysadmins and developers will use StackOverflow, Google, Q & A site about Linux/Unix for copy and pasting code. It can lead to lots of bad code and errors. For example, catastrophic rm command as VAR not defined at all:
rm -rf "$VAR/*"
You can fix many such problems while writing shell scripts using a linting tool such as shellcheck. Let us stay safe and perform shell script analysis with ShellCheck tool.

Installing ShellCheck

The simplest way to install ShellCheck locally is through your package managers such as apt/apt-get/yum and friends as per your Linux distro or Unix variant. Run commands as per your distro.

Install ShellCheck on a Debian/Ubuntu Linux

Type the following apt command/apt-get command:
$ sudo apt install shellcheck
Sample outputs:

[sudo] password for vivek: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,841 kB of archives.
After this operation, 15.5 MB of additional disk space will be used.
Get:1 artful/universe amd64 shellcheck amd64 0.4.6-1 [1,841 kB]
Fetched 1,841 kB in 42s (43.4 kB/s)                                                                                                                                                                               
Selecting previously unselected package shellcheck.
(Reading database ... 196100 files and directories currently installed.)
Preparing to unpack .../shellcheck_0.4.6-1_amd64.deb ...
Unpacking shellcheck (0.4.6-1) ...
Setting up shellcheck (0.4.6-1) ...
Processing triggers for man-db ( ...

Install ShellCheck on a CentOS/RHEL/Fedora/Oracle Linux

First enable EPEL repo on a CentOS/RHEL:
$ sudo yum -y install epel-release
Next, type the following yum command:
$ sudo yum install ShellCheck
Sample outputs:

Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base:
 * epel:
 * extras:
 * updates:
Resolving Dependencies
--> Running transaction check
---> Package ShellCheck.x86_64 0:0.3.5-1.el7 will be installed
--> Processing Dependency: ghc(ShellCheck-0.3.5-297097a7f5fa37100847be7f096be51e) for package: ShellCheck-0.3.5-1.el7.x86_64
Dependencies Resolved
 Package                Arch         Version                  Repository  Size
 ShellCheck             x86_64       0.3.5-1.el7              epel       495 k
Installing for dependencies:
 ghc-ShellCheck         x86_64       0.3.5-1.el7              epel       540 k
 ghc-array              x86_64         epel       113 k
 ghc-base               x86_64         epel       1.6 M
 ghc-bytestring         x86_64        epel       182 k
 ghc-containers         x86_64         epel       287 k
 ghc-deepseq            x86_64         epel        45 k
 ghc-directory          x86_64         epel        59 k
 ghc-filepath           x86_64         epel        60 k
 ghc-json               x86_64       0.7-4.el7                epel        96 k
 ghc-mtl                x86_64       2.1.2-27.el7             epel        33 k
 ghc-old-locale         x86_64         epel        50 k
 ghc-parsec             x86_64       3.1.3-31.el7             epel       105 k
 ghc-pretty             x86_64         epel        57 k
 ghc-regex-base         x86_64       0.93.2-29.el7            epel        28 k
 ghc-regex-compat       x86_64       0.95.1-35.el7            epel        15 k
 ghc-regex-posix        x86_64       0.95.2-30.el7            epel        47 k
 ghc-syb                x86_64       0.4.0-35.el7             epel        39 k
 ghc-text               x86_64           epel       379 k
 ghc-time               x86_64         epel       187 k
 ghc-transformers       x86_64           epel       100 k
 ghc-unix               x86_64         epel       160 k
Transaction Summary
Install  1 Package (+21 Dependent packages)
Total download size: 4.6 M
Installed size: 28 M
Is this ok [y/d/N]: y
Downloading packages:
(1/22): ghc-bytestring-       | 182 kB   00:09     
(2/22): ghc-array-             | 113 kB   00:09     
  ghc-parsec.x86_64 0:3.1.3-31.el7                                             
  ghc-pretty.x86_64 0:                                         
  ghc-regex-base.x86_64 0:0.93.2-29.el7                                        
  ghc-regex-compat.x86_64 0:0.95.1-35.el7                                      
  ghc-regex-posix.x86_64 0:0.95.2-30.el7                                       
  ghc-syb.x86_64 0:0.4.0-35.el7                                                
  ghc-text.x86_64 0:                                             
  ghc-time.x86_64 0:                                           
  ghc-transformers.x86_64 0:                                     
  ghc-unix.x86_64 0:                                           

If you are using a Fedora Linux, run the following dnf command:
$ sudo dnf install ShellCheck

Install ShellCheck on an Arch Linux

Type the following pacman command:
$ sudo pacman -S shellcheck

Installing ShellCheck on a Gentoo Linux

Type the following emerge command:
$ sudo emerge --ask shellcheck

Install ShellCheck on an OpenSUSE Linux

Run the following zypper command:
$ sudo zypper in ShellCheck

macOS Unix install ShellCheck

Try the following port command if you are using MacPorts:
$ port install shellcheck
If you use Homebrew on a macOS/OS X, install Homebrew on macOS and then type the following brew command:
$ brew install shellcheck

Alpine Linux install ShellCheck

Execute the apk command:
# apk add shellcheck

How to use ShellCheck

Let us see my sample shell script with the cat command:
$ cat -n backupme
Sample outputs:

     1	#!/bin/bash
     2	t="/tmp/exclude.$$"
     3	source ~/.backup.conf
     4	>$t
     5	for w in $WHATNOT
     6	do
     7		echo $w >> $t
     8	done
     9	rsync $OPT -avr --exclude-from=$t  $WHAT $SERVER:$WHERE
    10	rm -rf $t

Run shellcheck backupme in the terminal:
$ shellcheck backupme
Sample outputs:

Fig.01: ShellCheck in action (click to enlarge)

The shellcheck asked me to fix unquoted variables and other issues. Here is my updated script as per warnings:
$ cat -n backupme
Sample outputs:
     1	#!/bin/bash
     2	t="/tmp/exclude.$$"
     3	source ~/.backup.conf
     4	touch $t
     5	for w in $WHATNOT
     6	do
     7		echo "$w" >> $t
     8	done
     9	rsync "$OPT" -avr --exclude-from=$t  "$WHAT" "$SERVER:$WHERE"
    10	rm -rf "$t"

Another session using shellcheck a shell script static analysis tool:

In /home/vivek/bin/faqtoc line 2:
     ^-----------------^ SC2124: Assigning an array to a string! Assign as array, or use * instead of @ to concatenate.

In /home/vivek/bin/faqtoc line 5:
[ $? -eq 0 ] && { echo -n "$code" | xclip -sel clip; }
  ^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.

For more information: -- Assigning an array to a string! A... -- Check exit code directly with e.g...

How to integrate shellcheck in your text editor

You can shellcheck with VIM or emacs text editor directly. I am using neomake vim plugin. It is an asynchronous linting and make framework for Neovim/Vim. I installed it using vim-plug plugin manager in my ~/.vimrc:
call plug#begin('~/.vim/plugged')
Plug 'pearofducks/ansible-vim'
" install and use neomake linting
Plug 'neomake/neomake'
call plug#end()

To install ansible-vim and neomake/neomake type the following command in vim:
To use plugin type the following command while writing/editing your bash/sh scripts:
Sample outputs:

Fig.02: Neomake displaying warning/errors with shellcheck


Overall it is an excellent little tool for improving and fixing your shell scripts. It can detect many common mistakes and errors. For more info see github page.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 3 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersncdu pydf
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
3 comments… add one
  • Raul Baron Nov 7, 2017 @ 7:13

    Very interesting. Thanks for sharing !!

  • Charles Nov 22, 2017 @ 0:26

    I believe there’s a very small error in your catastrophic ‘rm’ example (rm -rf "/$VAR/*"). The first / makes the rm command fail with the message cannot access '//*': No such file or directory.
    By removing the first /, the catastrophic behavior is bound to happen if $VAR do not exists (rm -rf "$VAR/*").

  • Ahmadali Shafiee Feb 25, 2021 @ 16:58

    also, there’s a shellcheck extention for vscode for us GUI users 😁

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum