Bashis the fifth most-used programming language in the world, and the one that most programmers refuse to take seriously. This must change.
According to the 2025 Stack Overflow Developer Survey, 48.7% of developers worldwide use Bash. Not “have used at some point” – but use it, actively, as part of their working lives. That places Bash fifth overall, behind JavaScript, HTML/CSS, SQL, and Python; ahead of TypeScript. And the trajectory is striking: Bash jumped roughly fifteen percentage points in a single year, the largest year-on-year increase of any language in the survey.
I have been writing Bash professionally for over thirty years. Nearly half of all developers write Bash; and the overwhelming majority of them write it badly. I mean, really fucking badly.
Some stats: a 2022 study published in ACM Transactions on Software Engineering and Methodology analysed 1.35 million Bash scripts scraped from GitHub. The findings were pretty blunt: 80% of those scripts contained code smells. The most common problems were exactly what you would expect – quoting failures, word-splitting errors, missing error handling, sloppy structure. Basically, schoolboy errors.
This is the paradox. A mainstream language – used by more developers than TypeScript, running on 96.3% of the world’s top million web servers, present in every CI/CD (Continuous Integration / Continuous Delivery) pipeline and every container – treated with less engineering discipline than a weekend vibe coding project in Python.
Modern Bash Is Not What You Think
The objection I hear most often is that Bash is “just a shell”. A command-line interface, not a real language. This is usually said with a dismissive wave, as though the matter were settled decades ago and no further investigation is warranted. The people who say this are thinking of Bash circa 1995. They are not wrong about 1995; but they are badly wrong about now.
And just to be clear: I am not talking about
sh, or the ancient Bash 3.2 beloved of macOS and blinkered
Apple-tragics who have never questioned why their operating system ships
a shell from 2007. And BSD? Still stuck on sh – no Bash at
all; I mean, honestly, ffs. I am talking about modern Bash – 4.0 and
above – the language as it actually exists on every Linux system built
in the last fifteen years.
Bash 4.0, released in 2009, introduced associative arrays,
coprocesses, and mapfile. Bash 4.3 added name references –
declare -n – giving the language pointer-like indirection
for the first time. Bash 5.0 brought epoch timestamps and improved
nameref resolution. Bash 5.2, in 2022, rewrote the command substitution
parser entirely, replacing ad-hoc parsing with a recursive bison
grammar. And Bash 5.3, released in 2025, introduced no-fork command
substitution – ${ cmd; } – which captures output without
spawning a subshell. That is a genuine performance primitive.
Modern Bash has typed variable attributes via declare,
strict error handling via set -euo pipefail, proper scoping
with local, regular expression matching with
=~, and signal handling through trap. It is
unambiguously Turing-complete, and academic researchers at venues like
ACM and POPL
now treat it as a programming language worthy of formal analysis.
Bash has evolved, but sysadmins, programmers, and developers have not kept up.
Where Bash Actually Wins
The case for Bash is not sentimental; it’s practical, and the numbers are very specific. Bash starts in 2.8 milliseconds. Python takes 11.1 milliseconds – four times longer, and often much more. In a container image, a Bash environment occupies 12.5 megabytes. Python on Alpine takes 59.6 megabytes. When you are building minimal containers, deploying to resource-constrained environments, or running thousands of short-lived processes, these differences are not academic.
More importantly, Bash has zero dependencies. No
runtime to install. No package manager to configure. No virtual
environment to activate. No supply chain to audit for the language
itself. Compare this with Python, where a simple deployment script can
drag in pip, virtualenv, a requirements file with pinned versions, and a
prayer that nothing conflicts with the system Python that half your
other tools depend on. Anyone who has spent an afternoon debugging
ModuleNotFoundError in a CI pipeline that worked yesterday
knows exactly what dependency hell looks like. Bash does not have this
problem. It does not have dependencies. It is the
dependency.
In air-gapped networks, in regulated industries, in minimal containers where every megabyte counts – Bash is the language that is already present when nothing else is allowed to be. On 96.3% of the top million web servers, on 92% of cloud virtual machines, in every GitHub Actions runner, every GitLab CI executor, and every Jenkins agent – it is already there, waiting to be used.
And people do use it, at scale, for serious work. NVM, the Node Version Manager, has over 92,800 GitHub stars. It is written entirely in Bash. Acme.sh, the pure-shell ACME client for TLS certificates, has 46,200 stars. Pyenv, pi-hole, dokku – all Bash. These are not toys. They are critical infrastructure used by millions of developers daily.
The “right tool for the right job” argument actually favours Bash
more than its critics admit. If you are orchestrating CLI commands,
managing files, composing pipelines, running system health checks, or
scripting container entrypoints, Bash is not just adequate – it is the
native language of the problem domain. Wrapping aws,
kubectl, and terraform in Python’s
subprocess.run() adds complexity and indirection with no
compensating benefit. The CLI was designed for the shell; use it!
The Real Problem
So if Bash is this capable, and this widely used, why is 80% of the code so damn poor?
The ACM study is instructive. The dominant code smells were not obscure corner cases. They were quoting errors and word-splitting mistakes – the absolute fundamentals of the language. This is not a failure of Bash. It is a failure of education, of standards, and of professional attitude.
Bash is the only mainstream language that most developers learn
entirely by copying Stack Overflow answers. There is no university
course on shell scripting. There is no onboarding module. There is no
equivalent of Python’s PEP
8 or Go’s gofmt that new developers encounter in their
first week. Nobody sits a junior engineer down and says, “Here is how
you write a proper shell script.” They hand them a broken deployment
pipeline and wish them luck.
And when programmers do seek out tutorials, what they find
is worse than nothing; it’s simply atrocious. The top-ranked Bash
tutorials on the web – freeCodeCamp, W3Schools, GeeksforGeeks,
TutorialsPoint – uniformly teach unquoted variables, single-bracket
conditionals, and scripts with no error handling whatsoever. Not one of
them mentions set -euo pipefail.
The venerable TLDP Advanced Bash-Scripting Guide, which shaped a generation of shell scripters, still presents backtick substitution as a primary syntax, and has not been updated since 2014! On YouTube, channels with millions of subscribers teach scripts that silently swallow every error and continue blindly. These are not fringe resources. They are the front page of Google. They are where programmers learn Bash, and they are teaching it broken.
The result is cargo-cult scripting: patterns copied without understanding, errors propagated through generations of dumb tutorial sites, and a collective shrug when something breaks because “it’s just a script”.
These “shrugs” have consequences: On 30 October 2023, Cloudflare suffered a 37-minute outage affecting Workers KV – their globally distributed key-value store. The root cause was a deployment script that referenced the wrong environment. Not a complex distributed systems failure; not a subtle race condition, but a sloppy script that nobody reviewed with the same rigour they would have applied to a Python module.
“It’s just a script” may be the most expensive sentence in DevOps. Every CI/CD pipeline, every deployment workflow, every container entrypoint, every cron job – these are all “just scripts” until they take down production. The same developer who would never push an untested Python function will cheerfully commit a 200-line deployment script that has no error handling, no input validation, and no tests. They would not dream of skipping code review for a Go service. But the Bash that actually deploys that service? It gets a cursory glance at best.
The problem has never been the language. The problem is the attitude brought to the language. Fix the attitude, and the language performs exactly as well as any other.
Getting Serious
The tools exist. ShellCheck, with over 37,000
GitHub stars, is a static analyser that catches quoting errors,
undefined variables, and common pitfalls before they reach production.
Strict mode – set -euo pipefail – turns Bash from a
language that silently ignores errors into one that fails fast and fails
loudly. Testing frameworks like bats-core bring
structured testing to shell scripts. Formatters like shfmt enforce consistent
style.
And coding standards exist. We built one ourselves – the Bash Coding Standard – but the point is not the specific standard. The point is that the concept exists at all. That someone has sat down and codified what disciplined Bash looks like: how to declare variables, how to handle errors, how to structure a script, how to parse arguments. That the accumulated knowledge of decades of shell scripting has been organised into rules that can be taught, learned, checked, and enforced.
If you would not ship an unreviewed Python function to production,
then you should not ship an unreviewed Bash script. If you would not
write Go without go vet, do not ever write Bash without
ShellCheck. If you would not deploy a Java service without tests, do not
deploy a deployment script without tests. The double standard is
indefensible, and it is costing you money and reliability every single
week.
Bash is not going away. It is the fifth most-used language in the world and rising. It runs on virtually every server you own, and it is the connective tissue of your entire deployment infrastructure. It deserves engineering discipline. Give it some.
Gary Dean is the principal of Okusi Associates and co-founder of YaTTI (Indonesian Open Technology Foundation), and co-creator of the Bash Coding Standard.
Gary Dean