Getting Started with Bash

🐚 Topic 1 — Getting Started with Bash

Before writing a single line of code, it helps to understand what Bash actually is, how it relates to your terminal, and the basic mechanics of creating and running a script. This chapter covers all of that — by the end you will have written and executed your first working script and understand exactly what happened when you ran it.

1 — What is the Shell?

When you open a terminal on a Linux system, you are not talking directly to the operating system kernel. Between you and the kernel sits a programme called a shell — a command interpreter that reads what you type, works out what you mean, and asks the kernel to carry it out.

The Terminal
Window onto the shell
The terminal (or terminal emulator) is the window you see on screen. It handles display and keyboard input but has no intelligence of its own — it just passes what you type to the shell and displays what the shell sends back.
The Shell
The command interpreter
The shell reads your input, interprets it (expanding variables, glob patterns, redirections), and runs programmes or built-in commands. It also provides a complete programming language — loops, conditionals, functions, and variables.
The Kernel
The operating system core
The Linux kernel manages hardware, memory, processes, and the filesystem. The shell talks to the kernel on your behalf via system calls. As a script writer you rarely think about the kernel directly — that's the shell's job.
Bash
Bourne Again Shell
Bash (written in 1989 by Brian Fox) is the most widely used shell on Linux. It is the default shell on most Debian, Ubuntu, and Red Hat systems. The name is a pun on the original Bourne Shell (sh) that it replaced and extended.

Available Shells

ShellFull NameNotes
bashBourne Again ShellDefault on most Linux distros. The focus of this course.
shBourne Shell (or POSIX sh)The original. On modern systems /bin/sh is usually a link to dash or bash in POSIX mode. Fewer features than bash.
zshZ ShellDefault on macOS since Catalina. Very similar to bash with extra features.
fishFriendly Interactive ShellUser-friendly with autosuggestions but not POSIX-compatible.
dashDebian Almquist ShellLightweight and fast. Ubuntu uses it as /bin/sh for system scripts.
🐧 Check which shell you are using
# Print your current shell echo $SHELL /bin/bash # Print the exact version of bash installed bash --version GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu) # List all shells installed on the system cat /etc/shells

2 — What is a Shell Script?

A shell script is nothing more than a plain text file containing a sequence of commands — exactly the same commands you would type at the terminal, one per line. Instead of typing them one at a time, you write them all in a file and tell the shell to run the file. This lets you automate repetitive tasks, combine commands into reusable tools, and build complex workflows.

The simplest possible script
A script that prints a message and shows today's date. Save this as hello.sh.
#!/bin/bash # My first bash script echo "Hello, World!" echo "Today is: " date

That is a complete, working script. The following sections explain each part of it.

3 — The Shebang Line

The very first line of a script is special. The two characters #! (called a shebang or hashbang) followed by a path tell the operating system which interpreter to use to run this file.

#!/bin/bash

When the kernel sees a file starting with #!, it hands the file to the programme named after the !. In this case it runs /bin/bash and passes the script to it as input.

Common shebang lines
#!/bin/bash # use bash explicitly #!/usr/bin/env bash # find bash via PATH (more portable) #!/bin/sh # use the system's POSIX shell (dash on Ubuntu) #!/usr/bin/env python3 # same mechanism works for Python scripts
Which shebang should I use? Use #!/bin/bash when you want bash-specific features (arrays, [[ ]], process substitution). Use #!/usr/bin/env bash when you need portability across systems where bash may not be in /bin. Use #!/bin/sh only when you intentionally want POSIX-only compatibility.
⚠️ No shebang = unpredictable behaviour. Without a shebang line, the script will be run by your current shell — which might not be bash. Always include a shebang on the first line.

4 — Making a Script Executable

A newly created text file is not executable by default. Linux uses a permissions system to control who can read, write, and execute files. Before you can run a script with ./script.sh, you must grant it execute permission.

🐧 Grant execute permission with chmod
# Create the script file nano hello.sh # Check the current permissions ls -l hello.sh -rw-r--r-- 1 philip philip 62 Jun 9 10:00 hello.sh # rw-r--r-- = owner can read/write, others can only read. Nobody can execute. # Grant execute permission to the owner chmod +x hello.sh # Verify the permission change ls -l hello.sh -rwxr-xr-x 1 philip philip 62 Jun 9 10:00 hello.sh # The 'x' bits confirm execute permission is now set.

Understanding Permission Notation

CharactersWhoMeaning
rwxOwner (you)Read, Write, Execute
r-xGroupRead, no Write, Execute
r-xOthers (everyone else)Read, no Write, Execute
💡 chmod 755 vs chmod +xchmod +x adds execute permission for everyone (owner, group, others). chmod 755 does the same but also sets read/write for owner and read-only for everyone else. For personal scripts, chmod +x is fine. For scripts shared across users, chmod 755 is more explicit.

5 — Ways to Run a Script

There are three main ways to run a bash script, each with slightly different behaviour:

🐧 Three ways to run a script
# ── Method 1: Direct execution (requires chmod +x) ──────────────── ./hello.sh # The ./ means "in the current directory". The kernel reads the shebang # and launches /bin/bash to run the script. # ── Method 2: Call bash explicitly (no chmod needed) ────────────── bash hello.sh # Tells bash directly to interpret the file. The shebang line is ignored # (it becomes just a comment) because you specified the interpreter. # ── Method 3: Source the script (dot command) ───────────────────── source hello.sh # or equivalently: . hello.sh # Runs the script in the CURRENT shell session, not a new child process. # Variables and functions defined in the script persist after it finishes. # Useful for scripts that set environment variables (e.g. .bashrc).
MethodNew process?Needs chmod +x?Best used for
./script.shYesYesNormal script execution
bash script.shYesNoQuick testing, debugging
source script.shNoNoScripts that set variables/aliases
Why ./ ? On Linux, the current directory is deliberately not included in the PATH for security reasons. Without ./, the shell would search your PATH for a command named hello.sh and find nothing. The ./ prefix explicitly says "look in the current directory".

6 — Comments

A comment is text in a script that the shell ignores completely. Comments exist purely for the human reader. In bash, anything from a # character to the end of the line is a comment — except for the shebang on line 1.

Comment styles
#!/bin/bash # ───────────────────────────────────────────────────── # Script: backup.sh # Purpose: Creates a compressed backup of a directory # Author: Philip # Date: 2026-06-09 # ───────────────────────────────────────────────────── echo "Starting backup..." # inline comment — comes after code # The next line creates the archive tar -czf backup.tar.gz /home/philip/documents
💡 Good comments explain why, not what. The code already shows what is happening — a good comment explains the reasoning behind it. Instead of # increment counter (obvious), write # skip the header line in the CSV (explains purpose).

7 — Script Structure and the PATH

Typical Script Layout

A well-structured script template
#!/bin/bash # ───────────────────────────────────────────── # Script name and one-line description # ───────────────────────────────────────────── # ── Configuration / constants ────────────── LOG_FILE="/var/log/myscript.log" MAX_RETRIES=3 # ── Functions ────────────────────────────── greet() { echo "Hello, $1!" } # ── Main logic ───────────────────────────── greet "World" echo "Script complete."

Adding Scripts to your PATH

Once you have a collection of scripts you use regularly, you can place them in a directory and add that directory to your PATH so you can run them from anywhere without typing ./.

🐧 Add ~/bin to your PATH
# Create a personal scripts directory mkdir -p ~/bin # Copy your script there cp hello.sh ~/bin/hello # Add ~/bin to PATH permanently by adding this line to ~/.bashrc echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc # Apply the change in the current session source ~/.bashrc # Now you can run the script from anywhere hello Hello, World!
Many modern Linux distributions already include ~/bin in PATH if the directory exists — check with echo $PATH first.

8 — A First Look at Debugging

Even in a simple script, things can go wrong. Bash has a built-in debug mode that prints each command before executing it — invaluable when a script isn't behaving as expected.

🐧 Running a script in debug mode
# Run with -x to see every command as it executes bash -x hello.sh + echo 'Hello, World!' Hello, World! + echo 'Today is: ' Today is: + date Mon Jun 9 10:15:32 BST 2026 # Or add set -x inside the script to enable debug mode from that point #!/bin/bash set -x # turn debug on echo "hello" set +x # turn debug off
The + prefix in debug output marks commands executed by bash. We cover error handling and debugging in depth in Topic 11.

✏️ Exercises

Apply what you have learned in this chapter. Try each exercise yourself before looking at the sample solution.

Exercise 1
Write a script called sysinfo.sh that prints the following on separate lines: the current date and time, your username, your home directory, and the hostname of the machine.
Hint: the commands date, whoami, echo $HOME, and hostname will each give you one of the pieces of information you need.
Sample Solution
#!/bin/bash # sysinfo.sh — prints basic system information echo "Date and time : $(date)" echo "Username : $(whoami)" echo "Home directory: $HOME" echo "Hostname : $(hostname)"

The $( ) syntax is called command substitution — it runs the command inside and inserts its output into the string. We cover this in more detail in Topic 3.

Exercise 2
Write a script called greet.sh that accepts a name as a command-line argument and prints Hello, [name]!. If no argument is provided, it should print Hello, World! instead.
Hint: $1 holds the first argument passed to the script. You can check whether it is empty with if [ -z "$1" ].
Sample Solution
#!/bin/bash # greet.sh — greets a named person, or the world if [ -z "$1" ]; then echo "Hello, World!" else echo "Hello, $1!" fi

Don't worry if the if syntax looks unfamiliar — conditionals are covered fully in Topic 5. The important concept here is $1 for the first argument.

Exercise 3
Create a script called setup_project.sh that creates a project directory structure. It should create a directory called my_project containing three subdirectories: src, docs, and tests. It should then print a confirmation message listing each directory created.
Hint: mkdir -p creates a directory and any missing parent directories in one command.
Sample Solution
#!/bin/bash # setup_project.sh — creates a standard project layout mkdir -p my_project/src mkdir -p my_project/docs mkdir -p my_project/tests echo "Project structure created:" echo " my_project/" echo " my_project/src" echo " my_project/docs" echo " my_project/tests"

Bonus: Try rewriting this using a loop over an array of directory names — something to revisit after Topics 6 and 8!

Exercise 4
Write a script called mypath.sh that prints each directory in your PATH environment variable on its own line, with a line number in front of each one. For example: 1: /usr/local/bin, 2: /usr/bin, etc.
Hint: $PATH contains directories separated by colons. You can split it by replacing : with newlines using echo "$PATH" | tr ':' '\n'. Piping through a loop with a counter will let you add line numbers.
Sample Solution
#!/bin/bash # mypath.sh — lists PATH directories with line numbers count=1 echo "$PATH" | tr ':' '\n' | while read -r dir; do echo "$count: $dir" count=$(( count + 1 )) done

This exercise previews pipes, loops, and arithmetic — all covered in upcoming topics. If the solution looks complex now, revisit it after Topics 3 and 6.