Writing Your First Shell Script
A shell script is just a plain text file that holds a list of commands you would otherwise type one by one into the terminal. Instead of repeating those commands by hand every time, you save them in a file and run the whole file at once. In this guide you will build, save, and run your very first Bash script on Ubuntu, then learn what each step actually does so the magic feels less magic and more like a tool you control.
This is the foundation of almost everything in DevOps and Linux server administration. Deployments, backups, server setup, and scheduled jobs are all just shell scripts under the hood. Getting comfortable here pays off everywhere later.
What you need first
You only need a terminal and a text editor. On Ubuntu (this guide targets Ubuntu 22.04 LTS and 24.04 LTS) both are already installed. Bash (the “Bourne Again SHell”, the program that reads and runs your commands) is the default shell, so there is nothing to install.
Open a terminal with Ctrl + Alt + T. Confirm Bash is available:
bash --version
Output:
GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
If you see a version number, you are ready.
Step 1 — Create the file
A script file is just a text file. By convention we give it a .sh extension (for “shell”) so humans can tell at a glance what it is. Linux does not actually require the extension, but it is good practice.
Create an empty file called script.sh using the touch command (a small tool that creates an empty file if one does not exist):
touch script.sh
Now open it in nano, a simple built-in text editor that is friendly for beginners:
nano script.sh
Tip: Prefer a graphical editor?
gedit script.shopens Ubuntu’s default GUI editor, andcode script.shopens VS Code if you have it installed. Any plain text editor works — just never use a word processor like LibreOffice Writer, because it adds hidden formatting that breaks scripts.
Step 2 — Add the shebang and commands
Type the following into the editor:
#!/usr/bin/env bash
# This is my first shell script.
echo "Hello, DevOps!"
echo "Today is:"
date
Let us break down every line:
| Line | What it does |
|---|---|
#!/usr/bin/env bash | The shebang — the first line that tells Linux which program should run this file (Bash). Without it, the system may not know how to execute your script. |
# This is my first... | A comment. Any line starting with # (except the shebang) is ignored by Bash. Comments are notes for humans. |
echo "Hello, DevOps!" | echo prints text to the screen. The text in quotes is exactly what gets shown. |
date | Runs the real date command, which prints the current date and time. This proves your script can run any command, not just print text. |
In nano, save with Ctrl + O then Enter, and exit with Ctrl + X.
Step 3 — Make it executable
Right now the file is just text. Linux will not run it as a program until you give it execute permission — a flag on the file that says “this is allowed to run”. You add that flag with chmod (short for “change mode”):
chmod +x script.sh
The +x means “add the execute permission”. You can confirm it worked by listing the file with its permissions:
ls -l script.sh
Output:
-rwxr-xr-x 1 ubuntu ubuntu 95 Jun 15 10:42 script.sh
See the three x letters in -rwxr-xr-x? Those are the execute flags. Before chmod +x, that line would have read -rw-r--r-- with no x at all.
Step 4 — Run it
Now run your script:
./script.sh
Output:
Hello, DevOps!
Today is:
Sun Jun 15 10:42:31 UTC 2026
That is it — you wrote and ran a real program.
Why the ./ in front?
For security, Linux does not look in your current folder when you type a command name. If it did, a malicious file named ls dropped into a folder could hijack a normal command. The ./ means “the file named script.sh right here in this current directory”, removing all ambiguity. The . is shorthand for “current directory”.
Two ways to run a script
There is another way to run a script, and knowing the difference helps you debug.
| Command | Needs +x? | What happens |
|---|---|---|
./script.sh | Yes | Linux reads the shebang line and runs the file with that interpreter. The normal, real-world way. |
bash script.sh | No | You explicitly hand the file to Bash, which ignores the shebang and permissions entirely. Handy for a quick test. |
Gotcha: If you ever see
bash: ./script.sh: Permission denied, you forgotchmod +x. If you seecommand not foundwhen you typed justscript.sh, you forgot the./. These are the two most common first-day errors — now you know both fixes.
A slightly more useful example
Printing text is fine, but scripts shine when they automate real work. Here is one that reports basic system info — the kind of thing you would actually run on a server:
#!/usr/bin/env bash
echo "===== System Report ====="
echo "Hostname: $(hostname)"
echo "Logged in as: $(whoami)"
echo "Uptime:"
uptime -p
The $( ... ) syntax is command substitution: Bash runs the command inside the parentheses and drops its output right into the line. Save it as report.sh, run chmod +x report.sh, then ./report.sh:
Output:
===== System Report =====
Hostname: web-01
Logged in as: ubuntu
Uptime:
up 3 days, 5 hours, 12 minutes
Best Practices
- Always start scripts with the shebang
#!/usr/bin/env bashso they run with the right interpreter no matter where they live. - Give scripts a
.shextension and a clear, descriptive name likebackup-database.shso future-you knows what it does. - Add comments (
#) to explain why something is done, not just what — the code already shows the what. - Run
chmod +xonce when you create the script; you do not need to repeat it unless permissions get reset. - Test new scripts with
bash script.shfirst if you suspect a permissions issue, then switch to./script.shfor normal use. - Keep scripts in a dedicated folder (for example
~/scripts) and never run a downloaded script before reading it — running untrusted scripts is one of the easiest ways to compromise a server.