Part 3. Debugging a shell script
In this final part, you’re going to use the ShellCheck
extension you just
installed to debug a short Bash program.
Your task
Create a new file in Visual Studio Code by selecting New File…
from the
File
menu. Name the file hello.sh
and save it in your home directory.
Copy the short program below into hello.sh
and save the file.
#!/bin/bash
if [[ $# -gt 0 ]]; then
user="$1"
else
user="$(whoami)"
fi
echo Hello ${user}, welcome to CS 241
The line that starts with #!
is called a
shebang and it tells the
operating system what program to use to run the file, namely /bin/bash
.
Next is a somewhat unusual looking if
statement that sets the variable
user
. If the user runs the script and passes foo
as an argument like this
$ bash hello.sh foo
then user
will be set to foo
. If the user runs the script with no arguments like this
$ bash hello.sh
then user
will be set to name of the current user by calling the whoami
program.
The final line of the program prints text. Notice that ${user}
is used to
get the value of the user
variable. (You can also use $user
without the
braces, but there are situations where the braces are required so I tend to
use braces all the time.)
Open a terminal in VS Code by pressing Ctrl-` (control-backtick). Run the program a few times with different arguments and pay close attention to how the program behaves.
$ bash hello.sh
$ bash hello.sh Stu Dent
$ bash hello.sh "Stu Dent"
$ bash hello.sh "Stu Dent"
Notice that $ bash hello.sh Stu Dent
didn’t include the Dent
portion
whereas when the quotation marks were used, the full name appeared. Bash uses
spaces to split the command into different parts. This is called word splitting.
Stu
and Dent
became
separate arguments passed to hello.sh
. By using quotation marks, the whole
string stays together as a single argument.
This will come up often when working with the terminal.
You may have noticed strange behavior with the final two examples. Namely,
"Stu Dent"
and "Stu Dent"
behaved identically:
$ bash hello.sh "Stu Dent"
Hello Stu Dent, welcome to CS 241
Where did the extra spaces go?
Look in VS Code and you’ll notice that ${user}
has a squiggly line under it.
Mouse over the line and you’ll see that the ShellCheck
extension has
reported an error here. You can see a list of all problems by opening the
Problems
pane by selecting Problems
from the View
menu.
ShellCheck
says, “Double quote to prevent globbing and word splitting.
shellcheck(SC2086).” Actually, the ShellCheck
extension merely runs the
shellcheck
program. If we run shellcheck
ourselves using the terminal as
shown below, it will give us some more detail:
$ shellcheck hello.sh
In hello.sh line 9:
echo Hello ${user}, welcome to CS 241
^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean:
echo Hello "${user}", welcome to CS 241
For more information:
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
In addition to showing the error, it also suggests and fix and provides a link for more information.
The underlying problem here is that ${user}
expanded to
Stu Dent
but this underwent word splitting when evaluating the echo
line. echo
takes any number of arguments and prints them out in a line with a single
space between them. So when executing the line
echo Hello ${user}, welcome to CS 241
it first expanded ${user}
giving
echo Hello Stu Dent, welcome to CS 241
This is split by spaces and thus executes exactly as if it had been written like this.
echo Hello Stu Dent, welcome to CS 241
Modify hello.sh
by following the suggestion given by shellcheck
and save
your file. Run the program again. This time, any spaces should be preserved in
the argument.
In general, when programming in Bash, you want to double-quote variables otherwise the variables undergo word splitting and you almost never want that.
See the ShellCheck Wiki for error SC2086 for more explanation as well as a
suggestion for a better way to use quotation marks in the echo
line in
hello.sh
.