X
Popular Searches

How to Use shfmt to Format Shell Scripts Better

Bash Shell

Yes, formatting is necessary and helps tremendously with understanding complex code. However, for those who write shell scripts often, double checking formatting can become a tedious task. This article will show you how to shortcut the work using shfmt!

What Is shfmt?

Developed by Dustin Krysak, shfmt is a Shell formatter, parser and interpreter. The project itself is hosted on GitHub and has a clear README and cleanly presented repository. The tool was developed in Go and supports the POSIX, Bash and mksh shells. This makes shfmt a truly universal program instead of being restricted to Bash only.

Installing shfmt

To install shfmt on your snap-enabled Linux distribution (Like Ubuntu and Mint), execute the following command in your terminal:

sudo snap install shfmt

Installing shfmt with snap

To install shfmt on your RedHat/Yum based Linux distribution (Like RHEL, Centos and Fedora), execute the following commands in your terminal:

Note: you will have to reboot your machine (or logout and re-login) after executing the first command and before executing the next commands.

sudo dnf install snapd
sudo snap install snap-store
sudo snap install shfmt
Advertisement

On RHEL and Centos you may also have to install the EPEL repository first.

Using shfmt

One the snap package is installed, you can start using shfmt.

shfmt - a compact tool for Shell formatting

Let us define a very poorly formatted and written script as test.sh as follows:

#!/bin/bash__
 echo 'not well formatted line 1'
  echo 'not well formatted line 2'
echo 'this line has extra spaces on the end > '            
func() {
  echo 'more unneeded spaces'
              echo 'way out'
 }
func ()

There are several issues with this script, the most prominent being the formatting thereof. But there is also an error/bug in the script: The function call func on the last line is followed by more brackets. A function call in Bash (rather than a function definition) should only have the name, not the brackets. It is a bit higher that the proper function definition happened.

Let’s see what shfmt thinks of this.

shfmt test.sh

A practical example for shfmt with error on incorrect function call

Whereas the output looks a little cryptic, note that the term foo (used here) and bar (not used here now) are often used in IT circles to indicate/represent any like idiom or element. foo here really refers to func.

Even then, the message remains a little cryptic until we realize, looking at the last line, that what is really happening is the start of a function definition (and not a function call) because the two brackets were included. This then explains why the message is telling us that something more is expected; must be followed by a statement. shmft is looking here for something like func(){ some_command[s]; }.

Advertisement

Bingo! This increases the functionality of shfmt to being a shell script validation/checker tool, though likely nowhere near a comprehensive one as the one we wrote about in using shellcheck to find and fix scripting bugs. Still, very handy indeed!

We fix our bug and now the input script test.sh reads as follows:

#!/bin/bash__
 echo 'not well formatted line 1'
  echo 'not well formatted line 2'
echo 'this line has extra spaces on the end > '            
func() {
  echo 'more unneeded spaces'
              echo 'way out'
 }
func

We again execute shfmt against the code and receive a much more suitable, and well formatted, output:

Using a two space indent with shfmt using the -i option

Great. We can now take this one level further and indicate to shfmt that we would like to use an indent/tab width of two spaces instead of a full tab. I always write code using two spaces as an indent/tab width, and use an additional space where a command on the next line closely relates to the previous one, like a continued command etc. though this does not happen often. Over more than 10 years, I have found the two spaces to be the personal and shared projects ideal.

Everyone and every project has to find their own ideal syntax, but note that if you use a large tab (8 spaces) like the formatting presented by shfmt in the example above, your code may become harder to read easily.

We will set the indent/tab width to two spaces using the -i option (which the --help defines as indent: 0 for tabs (default), >0 for number of spaces): shfmt -i 2 test.sh which will render the script as follows:

#!/bin/bash__
echo 'not well formatted line 1'
echo 'not well formatted line 2'
echo 'this line has extra spaces on the end > '
func() {
  echo 'more unneeded spaces'
  echo 'way out'
}
func
Advertisement

Great! However, we note that shfmt did not pickup on our deliberate error: #!/bin/bash__ is not correct, and should read #!/bin/bash instead.

The error both shfmt and shellcheck missed

There is thus still a use case for using shellcheck to find script bugs besides using shfmt to format scripts better. However, interestingly, in this particular case, even shellcheck failed to notice the issue. This shortcoming was reported to the shellcheck team so in due time this may be fixed.

If you are interested in learning more about Linux, you can review the Bash Automation & Scripting Basics Series, as well as the Bash Loops: for, while, and until Bash Loops: for, while, and until and Exporting Variables in Bash: the Why and How articles.

Wrapping up

Being able to write clean, well-formatted, and bug-free scripts becomes an easier job when you use a shell formatting tool like shfmt and a bug/error checker like shellcheck. Even then, as we saw, some things may go unnoticed even up to the moment where you run the script for the first time. shfmt is a small but effective utility which will help you format your scripts and code in accordance with your selected indents. Enjoy!

Roel Van de Paar Roel Van de Paar
Roel has 25 years of experience in IT & business, 9 years of leading teams, and 5 years in hiring & building teams. He worked for companies like Oracle, Volvo, Sun, Percona, Siemens, Karat, and now MariaDB in various senior, principal, lead, and managerial roles. Read Full Bio »

The above article may contain affiliate links, which help support CloudSavvy IT.