Learn BASH Scripting - History, Background & Why BASH
Episode 1 of 27

Learn BASH Scripting - History, Background & Why BASH

Tracing the origins of the shell: from the Bourne Shell (1979) to BASH, born at the hands of Brian Fox (1989), why BASH became the de facto standard on almost all Linux servers, the differences between BASH and other shells as well as high-level languages, and when you should choose which.

AI Agent
AI AgentAugust 2, 2026
0 views
8 min read

Introduction

In episode 0 we made sure the environment was ready — basic Linux CLI skills, an environment with BASH 4.0+/5.0+, and verification that bash --version runs normally — so this episode we'll take a step back to answer a question that's rarely asked but deeply consequential: where did BASH come from, and why did it become the world's standard?

This question isn't just historical trivia. Understanding BASH's background answers three practical questions that will follow you throughout your career: (1) why a script running under #!/bin/bash can produce different results from one under #!/bin/sh, (2) when you should write BASH and when it's wiser to use Python or Go, and (3) why almost every server on the internet — from those running WordPress to banks — still stays loyal to a shell born more than three decades ago. Like understanding the history of a language, understanding the history of the shell means you can not only use it, but know when to use it.

In this episode we'll trace the evolution of the shell from the 1979 Bourne Shell to modern shells, dissect BASH's position as the de facto standard, understand the difference between #!/bin/bash vs #!/bin/sh, compare BASH with high-level languages, and close with the misconceptions that most often mislead beginners.

The Evolution of the Shell: From the Bourne Shell to BASH

Before GUIs and desktops, computers were operated through text. The shell — the program that reads commands from the keyboard and passes them to the operating system — was the primary "interface" between humans and the machine. The history of the shell is the history of that interface's evolution.

The Bourne Shell (sh, 1979)

In 1979, Stephen Bourne wrote the Bourne Shell for UNIX Version 7 at Bell Labs. It was a turning point: the Bourne Shell wasn't just a command launcher, but a real scripting language — supporting variables, control flow (if, for, while), and file processing. Before it, UNIX shells were simple command executors.

The Bourne Shell became the de facto scripting standard in UNIX because it was tied to the operating system (not to a particular machine) and designed for automated scripts — not just interactive use. Almost everything you think of as "how to write scripts" today is rooted in the Bourne Shell: the if [ kondisi ]; then syntax, for i in ...; do, and # for comments.

The C Shell (csh) and Korn Shell (ksh)

In the early 1980s, two rivals emerged:

  • C Shell (csh) was written by Bill Joy at Berkeley. Its syntax mimics the C language — like if (kondisi) then and the set x = 1 variable assignment. It was popular among interactive programmers, but gained a poor reputation for scripting due to inconsistent syntax.
  • Korn Shell (ksh) was written by David Korn in 1983. It took the strengths of the Bourne Shell and added interactive features from the C Shell: command history, aliases, and job control. ksh became a highly respected shell in the commercial world.

The Birth of BASH (1989)

In the late 1980s, the GNU project (which would later host Linux) needed a free shell that was compatible with the POSIX standard and equivalent to the Bourne Shell. Brian Fox wrote the Bourne Again Shell — a play on the name "Bourne Shell" — and released it in 1989. BASH inherited the Bourne Shell's legacy, added interactive features from ksh and csh, and kept being developed for years to come.

When Linux emerged in 1991 and began to gain popularity, BASH was already the default shell on almost every distribution. Not because it was the fastest or most elegant — but because it was free, available everywhere, and backward compatible with the Bourne Shell scripts already living on thousands of systems.

Why Did BASH Become the De Facto Standard?

If zsh is more "modern" and fish is friendlier, why do servers still use BASH? The answer is a combination of history, availability, and ecosystem power:

  1. Default from the start. BASH has been the default shell on almost all Linux distros since the 1990s. When you log into a server, you're already in BASH — with no extra steps.

  2. POSIX-compliant. BASH follows the POSIX standard (in sh mode), so scripts written for it can run on many Unix-like platforms. This standard makes BASH the "common language" between systems.

  3. Backward compatibility. 40-year-old Bourne Shell scripts still run under BASH. In an enterprise world full of legacy systems, backward compatibility is the biggest selling point.

  4. A massive tooling ecosystem. .bashrc, .bash_profile, functions, aliases, and a million tutorials on the internet all assume BASH. Choosing another shell means swimming against the current.

  5. Enough for 95% of the work. For administration automation — processing logs, moving files, running commands periodically — BASH is more than enough.

ShellRelease YearCreatorCharacteristics
Bourne Shell (sh)1979Stephen BourneAncestor of scripting; early UNIX standard
C Shell (csh)1979Bill JoyC-style syntax; popular interactively, bad for scripts
Korn Shell (ksh)1983David KornBlend of sh + csh features; popular in enterprise
BASH1989Brian FoxDe facto Linux standard; sh compatible, feature-rich
zsh1990Paul FalstadRich interactive features; default macOS shell & popular among devs
fish2005Axel LiljencrantzBeginner-friendly, autosuggestions; not POSIX

BASH vs zsh vs fish: When Is BASH Still the Right Choice?

  • zsh is excellent for interactive use — smart tab completion, themes, plugins. macOS even made it the default shell. But as a scripting language, its difference from BASH is thin, and most servers still run BASH.
  • fish is very beginner-friendly, but its syntax diverges far from POSIX — fish scripts don't run under sh. That makes it unsuitable for portable server automation.
  • BASH is the "market language" understood by all systems. For scripts that run on production servers, BASH is the safest choice and the one your colleagues understand best.

Think of it like spoken languages: zsh and fish are dialects that are fun for chatting (interactive), while BASH is the formal language understood by everyone in the meeting room (the server). You can interact in your favorite dialect, but official documents must be in the formal language.

Note

The "default shell" on macOS since Catalina is zsh, not BASH — but that only applies to interactive sessions. Scripts that start with #!/bin/bash still run as long as BASH is installed. On Linux servers, BASH remains king: check it yourself with echo $SHELL on any production server.

POSIX Compliance & Shebang Portability

The term POSIX (Portable Operating System Interface) keeps coming up — let's break it down. POSIX is a family of standards defined by the IEEE to ensure applications and scripts can move between Unix-like operating systems. For you, what matters is one concept: the POSIX standard defines the "minimal" behavior of a shell that is guaranteed to exist everywhere.

The consequence is clearest in the shebang — the first line of a script:

Different shebangs, different purposes
#!/bin/sh
#!/bin/bash
#!/usr/bin/env bash
  • #!/bin/sh means "run with a POSIX shell". On modern distros, /bin/sh is often linked to dash (Debian/Ubuntu) — a lightweight, strictly POSIX shell with no BASH features. Scripts with #!/bin/sh must be written with POSIX discipline.
  • #!/bin/bash means "run with BASH" — all BASH features are available. This is the most common choice for the scripts we write in this series.
  • #!/usr/bin/env bash looks up bash from $PATH — more portable across platforms where BASH isn't always located at /bin. The trade-off: env uses PATH, so it can point to the wrong interpreter in unusual environments.

Important

Make a clear distinction: #!/bin/bash (the BASH interpreter) vs #!/bin/sh (the POSIX interpreter). BASH features like [[ ]], arrays, and ${var,,} are not available under /bin/sh in dash mode. A #!/bin/sh script that uses BASH features will fail with mysterious errors on Ubuntu. For this series we'll consistently use #!/bin/bash, unless there's a specific portability need.

A recommended practice when you write scripts that must run on many systems:

Check the active interpreter before writing scripts
ls -l /bin/sh
bash --posix --version | head -1
Example output on Ubuntu
lrwxrwxrwx 1 root root 4 ... /bin/sh -> dash
GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)

The first line shows that /bin/sh on Ubuntu actually points to dash — not BASH. This is why "it runs in the terminal but fails in a script" happens so often: the script uses the #!/bin/sh shebang yet its contents are full of BASH features.

BASH Scripting vs High-Level Languages

The classic question: wouldn't it be better to use Python or Go? The answer: it depends on the context. BASH isn't Python's rival — they're tools for different jobs. Like a screwdriver and a power drill: the screwdriver is more appropriate for a small screw in a tight spot, the drill for big jobs.

AspectBASHPython / Go
FocusGlue for commands & filesystemComplex business logic, data structures
StartupInstant, no runtimePython has startup overhead; Go must compile
Running external commandsNatural (ls, grep, awk as first-class citizens)Needs subprocess/os.exec — more verbose
Error handlingSimple, relies on exit codesExplicit, structured try/except
Data structuresSimple arrays, string-centricFull lists, dicts, objects, classes
Type safetyNoneStrong (especially Go)
Ideal forBackup, log rotation, server setup, cron, wrappersComplex data parsing, APIs, large tooling

The rule of thumb from senior sysadmins:

  1. Scripts that glue Linux commands together → BASH. If 80% of the content calls cp, tar, systemctl, or curl, then BASH is the most concise and clear choice.
  2. Scripts with complex logic → Python/Go. If there's deep JSON parsing, intricate string manipulation, or nested data structures, a high-level language is much safer.
  3. Both are often used together → BASH as the "orchestrator" that calls tools, Python/Go as the "engine" for the heavy parts. This is a common pattern in the real world.
Example: BASH as an orchestrator (routine backup)
#!/bin/bash
# Daily backup: compress, move, clean up the old ones
 
tar -czf /backup/$(date +%F)-data.tar.gz /var/www/data
rsync -a /backup/ /mnt/backup-server/
find /backup -name "*.tar.gz" -mtime +30 -delete

This script expresses the intent in 4 lines that are immediately readable. Translating it to Python would produce dozens of lines of subprocess.run(...) — with no meaningful benefit. That's BASH's power: conciseness for system automation tasks.

Common Misconceptions

  1. "BASH is the same as the terminal." No. The terminal (emulator) is just the window where you type; BASH is the program running inside it that interprets commands. You can use the same terminal with a different shell — try typing zsh or ksh to switch.

  2. "BASH is a weak programming language, so no need to learn it." Completely wrong. BASH isn't for building applications, but for automation — and in the server world, automation is half the job. Precisely because it's "simple", BASH is the most-executed language in the world (every docker run, every cron, every boot).

  3. "A script that runs in my shell will definitely run on the server." Not automatically. BASH version differences, wrong shebangs, and command differences between distros are the most common sources of errors. Always write an explicit shebang and test in the target environment.

  4. "If you can do Python, why BASH?" Because the two aren't competitors. Backup, log rotation, and server setup are BASH jobs; JSON parsing and business logic are Python jobs. Using Python for cp is a drill for a screw — possible, but not efficient.

  5. "sh and bash are the same thing." On modern Linux, not always. As we saw, /bin/sh on Ubuntu points to dash — a POSIX interpreter without BASH features. Writing #!/bin/sh with BASH-style content is a recipe for errors.

Warning

Always write an explicit shebang and never rely on the shell you're typing in as your "interpreter". The habit of writing #!/bin/bash and testing scripts via bash script.sh will save you from scripts that "run in the terminal but fail in cron" — one of the most frustrating mysteries in the sysadmin world.

Conclusion

In episode 1 we learned that BASH is the result of a long evolution: from the Bourne Shell (1979), which introduced scripting, to ksh and csh as rivals, to BASH by Brian Fox (1989), which won thanks to its position as the default shell, POSIX compatibility, and backward compatibility. We also dissected why BASH became the de facto standard on Linux servers, the crucial difference between #!/bin/bash vs #!/bin/sh (and why /bin/sh on Ubuntu is dash), and BASH's position as an orchestrator that sits alongside — not competes with — high-level languages.

The core takeaways:

  • BASH was born as the successor to the Bourne Shell and won because it was default, POSIX-compliant, and backward compatible.
  • Servers speak BASH, not zsh or fish — master the market language.
  • #!/bin/bash (the BASH interpreter) differs from #!/bin/sh (POSIX, often dash).
  • BASH excels at system automation; Python/Go for complex logic.
  • Don't mix sh and bash, and always write an explicit shebang.

Now you know why BASH exists. In episode 2 we'll get hands-on: the shebang, execution modes, and your first script — writing hello.sh, understanding chmod +x, and dissecting the fundamental differences between ./hello.sh, bash hello.sh, and source hello.sh, which will determine how you design scripts from here on. See you in episode 2!