A shell script is a text file containing a sequence of commands for the shell to read and run, one after another, as if a user had typed them at the terminal. The GNU Bash Reference Manual defines it plainly in its “Shell Scripts” section: when a file is given as the first non-option argument to Bash, and neither the -c nor the -s option is supplied, Bash reads and executes commands from that file, then exits. The file is the program; the shell is the interpreter.
What turns a list of commands into a useful program is that the shell is itself a full language. Beyond running external tools, a script can branch with if and case, loop with for and while, define functions, capture command output into variables, and react to failures. This gives the script author the same control flow found in a conventional programming language, wrapped around the ability to invoke any command on the system.
Scripts become first-class commands through a small set of conventions. The manual notes that a shell script can be made executable with the chmod command to turn on the execute bit; when Bash finds such a file while searching $PATH for a command, it creates a new instance of itself to execute it. The same section explains that a leading line beginning with #! names the interpreter for the file, which is why scripts so often start with a line like #! /bin/bash. With those two pieces in place, a script is run by name, indistinguishable from a compiled binary.
The reason shell scripts matter historically is leverage. Routine work that would otherwise be retyped, such as backups, installs, log processing, build steps, and deployment, gets captured once in a file and replayed reliably. Because the shell speaks the universal language of text and can drive every other tool, the script is the natural glue layer of Unix and Unix-like systems, holding together programs that were never designed to know about one another.
That role has made shell scripting one of the most durable skills in computing. The Bourne shell language of the late 1970s, later standardized by POSIX and extended by Bash, still describes how millions of automation scripts are written today. A modern container build, a continuous integration pipeline, or a server’s startup sequence is very often, at bottom, a shell script.
The trade-offs are real. Shell scripts are excellent for orchestration but awkward for heavy computation or complex data structures, and their quoting and word-splitting rules are a frequent source of bugs. The discipline of writing robust scripts, checking exit status, quoting variables, and failing loudly, is what separates a throwaway one-liner from production automation.