Introduction
This page is mainly information about the foundation. It’s a bit boring but essential that will help you appreciate why and how certain things behave the way they do once we start playing with the fun stuff (which I promise we’ll do in the next section). Taking the time to read and understand the material in this section will make the other sections easier to digest, so persevere and it will be worth your time.
So what exactly are they?
Think of a script for a play, movie, or TV show. The script tells the actors what to say and do. A script for a computer tells the computer what to do or say. In the context of Bash scripts, we are telling the Bash shell what to do.
A Bash script is a plain text file that contains a series of commands. These commands are a mix of commands that we would normally type ouselves on the command line (like ls or cp, for example) and commands that we might type on the command line, but usually wouldn’t (you’ll discover them in the next few pages). However, an important point to remember is:
anything you can run normally on the command line can be put into a script and it will do exactly the same thing. Similarly, anything you can put into a script can also be run normally on the command line and will do exactly the same thing.
You don’t need to change anything. Just type the commands as you normally would and they will behave as they normally would. It’s just that instead of typing them into the command line, we’re now entering them into a plain text file. In this regard, if you know how to do things on the command line, then you already know a bit in terms of Bash scripts.
It is a convention to give files that are Bash scripts a .sh extension (myscript.sh for example). As you may know (and if you’re not maybe you should consider checking out our Linux Tutorial), Linux is a system without extensions so a script doesn’t necessarily have to have this feature to work.
How do they work?
This is just a little bit of foreknowledge. You don’t need to understand this to write scripts, but it can be useful to know once you start getting into more complex scripts (and scripts that call and rely on other scripts once you start to get really elegant).
In the realm of Linux (and computers in general) we have the concept of programs and processes. A program is a binary data blob consisting of a series of instructions for the CPU and possibly other resources (images, sound files, and so on) organized into a package and typically stored on your hard drive. When we say that we are running a program, we are not actually running the program, but a copy of it that is called a process. What we do is copy those instructions and resources from the hard drive into the working memory (or RAM). We also allocated some RAM space for the process to store variables (to hold temporary job data) and some flags to allow the operating system (OS) to manage and track the process during its execution.
Essentially, a process is a running instance of a program.
There can be multiple processes representing the same program running in memory at the same time. For example, you could have two terminals open and be running the cp command on both. In this case there would be two cp processes currently existing in the system. Once they finish running, the system destroys them and there is no longer any process that represents the cp of the program.
When we are in the terminal we have a Bash process running to give us the Bash shell. If we start a script running, it doesn’t actually run in that process, but starts a new process to run inside. We will demonstrate this in the next section on variables and its implications should be clearer. For the most part, you don’t need to worry too much about this phenomenon, though.
How do we execute them?
Running a Bash script is pretty easy. Another term you may encounter is running the script (which means the same thing). Before we can run a script, it must have the execute permission set (for security reasons, this permission is usually not set by default). If you forget to grant this permission before running the script, you will receive an error message indicating you as such and no harm will be done.
Here are the contents of myscript.sh
Let’s break it down:
- Line 1 – It is what is known as the shebang. See below what this is.
- Line 2 – This is a comment. Anything after # does not run. It is for our reference only.
- Line 4 – It is the echo of the command that will print a message on the screen. You can type this command yourself on the command line and it will behave exactly the same.
- Syntax highlighting is there just to make it easier to read and isn’t something you need to do on your own files (remember they’re just plain text files).
Why
the ./
You may have noticed that when we execute a normal command (like ls) we simply type its name, but when running the previous script I put a ./ in front of it. When you simply type a name on the command line, Bash tries to find it in a series of directories stored in a variable called $PATH. We can see the current value of this variable using the echo command (you’ll learn more about variables in the next section).
The directories
are separated by ” : “
Bash only searches those specific directories and ‘t considers subdirectories or your current directory. It will review those directories in order and run the first instance of the program or script it finds.
The $PATH variable is an individual user variable, so each user of a system can configure it to suit themselves.
This is done for a few different reasons.
- It allows us to have several different versions of a program installed. We can control which one runs based on where it is on our $PATH.
- It allows comfort. As you saw above, the first directory for me is a bin directory in my home directory. This allows me to put my own scripts and programs there and then I can use them no matter where I am in the system by simply typing their name. You could even create a script with the same name as a program (to act as a wrapper) if you wanted slightly different behavior.
- Increases security: For example, a malicious user could create a script called ls that actually deletes everything in your home directory. You wouldn’t want to inadvertently run that script. But as long as it’s not in your $PATH that won’t happen.
If a program or script is not in one of your $PATH’s directories you can run it by telling Bash where to look to find it. To do this, include an absolute or relative path in front of the name of the program or script. You’ll remember that dot ( . ) is actually a reference to your current directory. Assuming this script is in my home directory, I could also have run it using an absolute path.
The Shebang (#!)
#!/bin/bash
This is the first line of the previous script. The character sequence of the hash exclamation mark (#!) is known as Shebang. Below is the path to the interpreter (or program) that should be used to execute (or interpret) the rest of the lines in the text file. (For Bash scripts it will be the path to Bash, but there are many other types of scripts and each has its own interpreter.)
Format is important here. The shebang must be on the first line of the file (line 2 will not do, even if the first line is blank). There should also be no spaces before the # or between the ! and the path to the interpreter.
While you can use a relative path for the interpreter, most of the time you’ll want to use an absolute path. You’ll probably run the script from a variety of locations, so absolute is the safest (and often also shorter than a relative path in this particular case).
It is possible to skip the line with the shebang and still run the script, but it is not wise. If you’re in a terminal and you run the Bash shell and run a script without a shebang, Bash will assume it’s a Bash script. Therefore, this will only work assuming that the user running the script is running it in a Bash shell and there are a variety of reasons why this may not be the case, which is dangerous.
You can also run Bash, passing the script as an argument.
While this is safe, it also involves typing unnecessarily every time you want to run the script.
Format
As we saw earlier, the format for the shebang was important (i.e. without spaces, it must be in the first line). There are many areas in Bash scripts where formatting is important. It usually involves spaces and the presence or absence of a space can be the difference between the command that works or not. I will point these out as we find them. Also get into the habit of being aware of the presence or absence of spaces when looking at code.
The main reason for this is that Bash was originally developed as an interface for users to interact with the system and later extended to have more powerful scripting capabilities. Many decisions regarding the behavior of it were made considering only the needs of the user and then the scripting capabilities had to be worked on, later, around those decisions. However, people generally don’t mind this, as Bash scripts are still an amazing tool for quickly and easily stitching existing programs into more powerful solutions.
I’ve seen students spend quite a bit of time frustrated because a snippet of code that looks perfectly fine doesn’t work. They are quite embarrassed when they discover the culprit (a space that should or should not be there). You’ll probably make this mistake several times before it sinks, so don’t worry too much, but the sooner you master it, the happier you’ll be 🙂
Code indentation is another area of formatting that is important. We will see the indentation of the code in section 5 (If Statements) when relevant. Indentation isn’t necessary, but it makes your code easier to read and makes it harder to make simple mistakes.