Format and statically check your shell script

ยท

5 min read

Here, I will introduce you to 2 tools; one for formatting your shell scripts and another for statically checking them for possible issues (this one instantly reminds me of eslint as a JavaScript developer!). So, let's get into it.

1. Formatting your shell script using shfmt

Initially, I found the link to shfmt's GitHub repo (which is here ) but instead of following setup instructions from there, I found installing it from Snap Store more straightforward: snapcraft.io/shfmt on my Ubuntu 20.04.

Basic usage is simple: shfmt -l -w path/to/script.sh

This command will overwrite your shell script with a formatted one.

Example:

A shell script before formatting it using shfmt:

#!/usr/bin/env bash

usage="Usage: leap.sh <year>"

main(){
    year=$1
    if [[ $(($year % 4)) -eq 0 ]] && [[ $(($year % 100)) -ne 0 ]]; then echo true
    elif [[ $(($year % 400)) -eq 0 ]]; then echo true
    else echo false 
    fi
}

check_args(){
    if ! [[ $(($#)) -eq 1 ]]||! [[ $1 =~ ^[0-9]+$ ]]; then
        echo $usage
        exit 1
    fi
}

check_args "$@"
main "$@"

After I format it using shfmt -l -w ./leap.sh, here is the output:

#!/usr/bin/env bash

usage="Usage: leap.sh <year>"

main() {
    year=$1
    if [[ $(($year % 4)) -eq 0 ]] && [[ $(($year % 100)) -ne 0 ]]; then
        echo true
    elif [[ $(($year % 400)) -eq 0 ]]; then
        echo true
    else
        echo false
    fi
}

check_args() {
    if ! [[ $(($#)) -eq 1 ]] || ! [[ $1 =~ ^[0-9]+$ ]]; then
        echo $usage
        exit 1
    fi
}

check_args "$@"
main "$@"

As you can observe, it did things like inserting proper spaces, moving code to the next line, and indenting code.

2. Statically checking your shell script with shellcheck

As a beginner in shell scripts, I find them hard to master, I feel there are lots of rules and nuances that one needs to know even for basic tasks.

Shellcheck statically checks your script for possible issues and even detects redundant things in your scripts. It saves you from late surprises!

Here is the link to its GitHub repo: github.com/koalaman/shellcheck. You will find how to install and use it in their README.

They also have a website to directly try it out on the web.

Example:

If I run shellcheck on formatted code from the above example, here is its output:

โฏ shellcheck ./leap.sh 

In ./leap.sh line 7:
        if [[ $(($year % 4)) -eq 0 ]] && [[ $(($year % 100)) -ne 0 ]]; then
                 ^---^ SC2004: $/${} is unnecessary on arithmetic variables.
                                               ^---^ SC2004: $/${} is unnecessary on arithmetic variables.


In ./leap.sh line 9:
        elif [[ $(($year % 400)) -eq 0 ]]; then
                   ^---^ SC2004: $/${} is unnecessary on arithmetic variables.


In ./leap.sh line 18:
                echo $usage
                     ^----^ SC2086: Double quote to prevent globbing and word splitting.

Did you mean: 
                echo "$usage"

For more information:
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
  https://www.shellcheck.net/wiki/SC2004 -- $/${} is unnecessary on arithmeti...

Shellcheck recommends me 2 fixes:

  1. Removing unwanted $ signs.
  2. Wrapping $usage in double quotes to avoid unexpected behaviors that can occur due to globbing and word splitting.

It also provides links for further reading on the suggestions it made, which is great!

Conclusion:

We saw two tools in this article, shfmt for formatting and shellcheck for statically analyzing and detecting issues in your shell scripts. Together they form a nice toolset for writing better shell scripts.

ย