Format and statically check your shell script
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:
- Removing unwanted $ signs.
- 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.