Your First Bash Script
Part of Essentials — Bash Scripting
First in the Essentials Bash series. Assumes you're comfortable with the terminal — if you need a refresher, start with Command Line Fundamentals. Next up: Variables and Quoting.
You've been running the same sequences of commands manually. A Bash script captures that sequence, makes it repeatable, and lets you hand it to a colleague or a CI pipeline. The gap between "I know the commands" and "I wrote the script" is smaller than it looks.
Where You've Seen This
If you've typed the same sequence of commands more than once, you've already felt the problem a script solves — it's just that sequence saved to a file and made repeatable. If you've used Windows batch files (.bat), the concept is identical; Linux just uses different syntax and bash is available everywhere by default.
A First Script
| system-info.sh | |
|---|---|
Three things to notice:
$(...)runs a command and substitutes its output inline — covered in depth in Variables and Quotingechosends output to stdout; pipelines and redirection work just like at the prompt- There's no
main()function — Bash runs top to bottom
The Shebang Line
That first line — #!/usr/bin/env bash — tells the OS which interpreter to run the script with. Without it, the shell has to guess, and it can guess wrong.
Uses env to find bash in $PATH. Survives if bash is installed in a non-standard location — common on macOS, BSD, or NixOS. The portable choice.
| Portable Shebang | |
|---|---|
Absolute path to bash on most Linux systems. Slightly faster (skips the env lookup). Fine for scripts you know will only run on standard Linux.
| Direct Path Shebang | |
|---|---|
POSIX shell — not Bash. More portable across Unix systems but loses Bash-specific features like [[ ]], arrays, and process substitution. Only use this if you genuinely need POSIX portability.
| POSIX Shell Shebang | |
|---|---|
The shell that called the script runs it. If your user's shell is zsh, the script runs as zsh. Unpredictable in automated contexts. Don't do this for scripts you'll share or schedule.
The rule of thumb: Use #!/usr/bin/env bash unless you have a specific reason to do otherwise.
Making It Executable
A new file isn't executable by default. Two steps to run it:
The ./ prefix tells the shell "look here, not in PATH." Without it, the shell searches PATH and won't find your script unless you've added its directory.
Read scripts before running them
chmod +x and ./run.sh is a common pattern in installation instructions. Read the script before executing it — it runs with your permissions.
See File Permissions for the full explanation of chmod and permission bits.
Running Without chmod +x
You can also run a script by passing it directly to bash:
| Run Without Executable Bit | |
|---|---|
This works even without chmod +x. Useful for quick tests, but the executable bit is the right approach for scripts you'll deploy or share.
Where to Store Scripts
Where a script lives determines who can run it and how easily:
For scripts only you need to run, install them to ~/bin and add it to your PATH:
| User-Scoped Scripts in ~/bin | |
|---|---|
Add ~/bin to your PATH in ~/.bashrc:
| Add ~/bin to PATH | |
|---|---|
Now you can run system-info from anywhere without ./.
For scripts that all users on the system should access:
| System-Wide Installation | |
|---|---|
/usr/local/bin/ is already in PATH for all users. Scripts here survive package manager updates (unlike /usr/bin/).
For shared tooling in a team environment:
| Company Script Directory | |
|---|---|
Add /opt/company/bin to PATH system-wide via /etc/profile.d/company.sh. Putting shared scripts under /opt/company/ keeps them out of package-managed paths and makes them easy to find.
Practice Exercises
Exercise 1: Write a Health Check Script
Write a script called health-check.sh that prints the following in a formatted block:
- Current user and hostname
- Load average (use
uptime) - Disk usage on
/(usedf -h) - Whether a specific process is running (use
pgrep -x sshd)
Solution
Exercise 2: Script Location Practice
Create a script called whoami-full.sh that prints your username, your primary group, and your home directory. Install it as a personal tool so you can run whoami-full from any directory without ./.
Solution
| whoami-full.sh | |
|---|---|
Install it:
Quick Recap
- The shebang line (
#!/usr/bin/env bash) tells Linux which interpreter to use — always include it chmod +x script.shmakes the file executable;./script.shruns itbash script.shruns a script without the executable bit — useful for one-off testing~/bin/for personal scripts,/usr/local/bin/for system-wide,/opt/company/bin/for team tooling- Add the directory to
$PATHso you can call scripts by name from anywhere
Further Reading
Command References
man bash— the full Bash reference; the "INVOCATION" section covers how scripts are startedman chmod— file permission bit reference
Deep Dives
- Google Shell Style Guide — the de-facto standard for team Bash scripts
- The Art of Command Line — command line mastery, including scripting fundamentals
Official Documentation
- GNU Bash Manual — the authoritative Bash reference
- Filesystem Hierarchy Standard — official spec for where things go on Linux
Exploring Python
- Why Python (Not Just Bash) — When your script grows into something bigger: the signals that mean Python is the right next step
What's Next?
Head to Variables and Quoting — how to declare variables, why quoting prevents catastrophic bugs, and how command substitution captures runtime values.