My First Script

Let’s write a script in bash! We’ll do this using the command line (with vim), but feel free to use any text editor.

Navigate to your home directory and open a new file named hello.sh.

NathanLui@local | ~ $ vim hello.sh

In vim, type i to enter insert mode and type:

#!/bin/bash

echo "Hello world!"

The first line is called the shebang (a portmanteau of hash (#) and bang (!)).1 It tells the operating system where to find the interpreter for the program. In this case we are telling the OS that this script can be read and run by bash which is located at /bin/bash. Many different interpreters can be used as an alternative to bash, for example #!/bin/python2.7 tells the OS that this script is written in python and it should be run using an old version of python (2.7) located at /bin/python2.7.

Recall that bash is both the shell and the scripting language, so bash commands we give, also known as the syntax, in the script are executed by the interpreting program /bin/bash.

Comments

The interpreter doesn’t treat this line as a program call since it starts with #, the bash comment symbol. Any text in a bash script that is preceded by a # will be ignored by the interpreter. Note that different languages have different comment symbols/types (e.g. (* OCaml *), % MATLAB, // Java, <!-- HTML -->, etc…). Comments within your code serve two purposes:
1) when other people read your code they understand your thinking and how you chose to implement the program, and
2) when you read your code, days, months, or years later, you understand your thinking and how you chose to implement the program

Figure 1. Always document your code. Comment wide and comment often, but don't comment the obvious! Check out this blog post to learn how to document well.2


Now back to our script, press esc to back out of insert mode and type :wq to write the file and quit vim. If you’re doing this in a graphical text editor save the file to the home directory with the name hello.sh.

Now let’s look for our new file in the home directory:

NathanLui@local | ~ $ ls
launchCodes.txt          playGame.sh          Presentation Slides
hello.sh

There it is! So lets run it with the command bash hello.sh.

NathanLui@local | ~ $ bash hello.sh
The command was not found or was not executable

That’s not good! We’re sure the file exists, so it must be our access modes. Let’s check:

NathanLui@local | ~ $ ls -l
-rw-r--r--   1 NathanLui  Users    33B Dec 21 13:21 hello.sh

There’s the issue, not a problem since it’s one we already know how to fix.

NathanLui@local | ~ $ chmod +x hello.sh             # n.b. the +x gives x 
NathanLui@local | ~ $ ls -l                         # permission to everyone
-rwxr-xr-x   1 NathanLui  Users    33B Dec 21 13:21 hello.sh

Now our program should run without a hitch.

NathanLui@local | ~ $ bash hello.sh
Hello world!

👏👏 You did it! 👏👏

Lets try something a bit more difficult. Open that script back up with vim hello.sh, add a variable called food and give it a value (like your favorite food):

#!/bin/bash

echo "Hello world!"
food="pizza"

Now let’s call that variable with:

echo "My favorite food is $food."

The $ tells the interpreter that we want the object stored in the variable food. Our full script now looks like:

When we run it, the script now prints:

NathanLui@local | ~ $ bash hello.sh             # no need to change permissions
Hello world!                                    # this time since we did it
My favorite food is pizza.                      # for this file earlier

Look at you go! One last thing that we should talk about is an environmental variable. An environmental variable is one whose value is set outside the program. Let’s edit our script one more time. Append the line:

echo "I am $age years old."

So our script is now:

But we haven’t declared the age variable yet. In some languages this would throw an error, but if we run our program we see:

NathanLui@local | ~ $ bash hello.sh
Hello world!
My favorite food is pizza.
I am  years old.

This is because bash automatically initializes uninitialized variables to null at first use (i.e. it has no value). So how do we get the script to print our age? We can initialize age as an environmental variable and export it to our script. We can do this in one step using export.

NathanLui@local | ~ $ export age=26
NathanLui@local | ~ $ bash hello.sh
Hello world!
My favorite food is pizza.
I am 26 years old.

You might be wondering why would ever need to do this. Often times we’ll be working with programs and complex algorithms that can’t be easily modified, or we’ll want to set variables once instead of every single time we run the program. These tasks can be easily accomplished using environmental variables.

Scripting is useful for more than telling the world your favorite food and how old you are. Its our primary way of sending instructions to the cluster. When we submit jobs to the CHEM cluster’s resource manager SLURM we do so in the form of shell scripts. More on that in the next chapter.

If you want to read more about the power of scripting I wholely recommend Al Sweigart’s book Automate the Boring Stuff with Python, a fantastic (and free) resource for budding programmers (and busy grad students).3


Previous
Linux Basics
Home
Next
SLURM Basics


References

(1) Shebang (Unix)
(2) How to write good documentation by Victoria Drake
(3) Automate the Boring Stuff with Python