What is Bash & Shell Scripting?
Every command you type into a Linux terminal is a small instruction to the computer. A shell script is just a text file that holds a list of those same commands, so the computer can run them for you — in order, every time, without you typing them by hand. In DevOps (the practice of automating how software is built, deployed, and operated), this is the foundation everything else is built on. If you can type it once, you can script it forever.
What is a shell?
A shell is the program that reads what you type, runs it, and shows you the result. When you open a terminal on an Ubuntu server, a shell is already waiting for you. It is the layer between you and the operating system (the core software, Linux, that manages the machine).
The most common shell on Linux is Bash — short for Bourne Again SHell. It is the default interactive shell on Ubuntu 22.04 and 24.04 LTS (LTS means “Long-Term Support”, a release Canonical maintains for years). You can confirm which shell you are using:
echo "$SHELL"
Output:
/bin/bash
What is a shell script?
A shell script is a plain text file containing the commands you would otherwise type one by one. Instead of running three commands manually every morning, you save them in a file and run the file. The computer executes each line top to bottom.
Here is the difference in practice. Typing manually:
sudo apt update
sudo apt upgrade -y
sudo systemctl restart nginx
The same thing saved as a script called update-server.sh:
#!/bin/bash
sudo apt update
sudo apt upgrade -y
sudo systemctl restart nginx
Now you run it with one command instead of three:
./update-server.sh
That first line, #!/bin/bash, is called a shebang. It tells Linux which program should run the file. You will learn more about it in Shebang and execution.
Why automation matters in DevOps
Automation is not about laziness — it is about correctness and scale. A human running ten commands by hand will eventually mistype one, skip one, or do them in the wrong order. A script does the exact same thing every single time.
| Manual commands | Shell scripts |
|---|---|
| Easy to forget a step | Every step runs, in order |
| Different each time a person does it | Identical, repeatable result |
| Hard to share with teammates | Just send the file |
| No record of what was done | The file IS the documentation |
| Slow on many servers | Run on 100 servers the same way |
These benefits map to the core reasons DevOps engineers script everything:
- Repeatability — the same input always produces the same output.
- Fewer mistakes — no fat-fingered typos at 2 a.m. during an incident.
- Speed — what took five minutes by hand runs in five seconds.
- Documentation — the script records exactly how a task is done.
- Scale — one script can configure one server or one thousand.
When to use a script vs. typing by hand: If you have done a task more than twice, or you will need to do it on more than one machine, write a script. For a true one-off you will never repeat, typing directly is fine.
Bash vs sh vs other shells
People often say “shell script” and “Bash script” as if they are the same thing, but they are not. sh is the original, minimal POSIX shell (POSIX is a standard that defines a baseline set of features every Unix-like shell must support). Bash is a newer, much more powerful shell that includes everything sh has, plus many extras like arrays and richer string handling.
| Shell | What it is | When to use it |
|---|---|---|
sh (dash on Ubuntu) | Minimal POSIX shell, very fast, very portable | Boot scripts, maximum portability across Unix systems |
bash | Feature-rich, the default interactive shell | Most automation; what this section teaches |
zsh | Bash-compatible with extra interactive features | Personal interactive use; popular with developers |
fish | Friendly, modern, NOT POSIX-compatible | Interactive comfort, not for portable scripts |
On Ubuntu, /bin/sh is actually dash (a small, fast sh implementation), not Bash. This matters: a script written with Bash-only features will break if run with sh. You can see the difference here:
ls -l /bin/sh
Output:
lrwxrwxrwx 1 root root 4 Jun 15 09:12 /bin/sh -> dash
Gotcha: Never run a Bash script with
sh script.sh. That forces it through dash, and any Bash-specific syntax (like[[ ... ]]or arrays) will fail with cryptic errors. Always start your script with#!/bin/bashand run it as./script.sh.
Everything you type can be scripted
This is the key mindset shift. There is no special “scripting language” separate from the commands you already use. The commands you type interactively — apt, systemctl, cp, grep, ufw — are the exact same commands you put in a script. A script is just those commands saved to a file.
That means the moment you learn a useful command at the terminal, you have also learned a line of a future script. Managing the systemd service manager (the tool Ubuntu uses to start and stop background services), opening firewall ports with ufw (Uncomplicated Firewall), copying config into /etc/nginx/sites-available — all of it can be wrapped in a script and run on demand or on a schedule.
#!/bin/bash
# A tiny but complete real script: back up Nginx config with a timestamp
backup_dir="/var/backups/nginx"
sudo mkdir -p "$backup_dir"
sudo cp -r /etc/nginx "$backup_dir/nginx-$(date +%Y%m%d-%H%M%S)"
echo "Backup complete."
Output:
Backup complete.
Once a script like this exists, you can run it from a scheduler with cron so it happens automatically every night — no human needed.
Best Practices
- Start every Bash script with the
#!/bin/bashshebang so it always runs with the right shell. - Give scripts clear, descriptive names ending in
.sh, likedeploy-app.sh, nots1.sh. - Add short
#comments explaining why a step exists, not just what it does. - Test a new script on a throwaway server or in a safe directory before running it on production.
- Quote your variables (
"$var") to avoid surprises with spaces and empty values. - Keep each script focused on one job; chain small scripts rather than building one giant file.
- Store scripts in version control (Git) so changes are tracked and reviewable.