Bash
itLinux
Bash
Bash is both a command interpreter and a programming language. You use it interactively to run programs. You also place commands in scripts to automate repeatable work.
The name means Bourne-Again Shell. Bash builds on the traditional Bourne shell and adds features for interactive work and programming. It is largely compatible with sh, but Bash also has its own syntax and behavior.
The mental model
A Bash command line is not passed to a program exactly as you type it. Bash processes the text first.
input
-> tokens and syntax
-> expansions
-> redirections
-> command execution
-> exit status
This processing model explains many surprises. A variable can become several arguments. A wildcard can become many filenames. A redirection can change where output goes before a command starts.
Quoting controls this processing. Single quotes preserve literal characters. Double quotes still allow selected expansions, including parameter expansion and command substitution. As a default, quote parameter expansions unless you specifically want word splitting or filename expansion.
name='Quarterly report'
printf '%s\n' "$name"
Here, "$name" becomes one argument. Without the double quotes, the result can be split into separate words.
Commands, builtins, and functions
Bash can run executable programs such as find and grep. It also provides builtins such as cd, read, and export. A builtin runs inside the shell, which lets it change shell state. An external program cannot change the current shell's working directory.
A shell function gives a name to a reusable group of commands. Functions share shell state unless you run them in a subshell.
show_location() {
printf 'Current directory: %s\n' "$PWD"
}
Use a function for small reusable behavior within a script or interactive session. Use a separate script when you need an independent command, clear inputs, or reuse across projects.
Data flows through arguments and streams
Commands receive positional arguments. They also work with standard input, standard output, and standard error.
arguments -> command
stdin -> command -> stdout
-> stderr
A pipeline connects one command's standard output to the next command's standard input.
printf '%s\n' alpha beta gamma | grep 'a'
Redirections connect streams to files or other file descriptors.
generate_report >report.txt 2>report.err
Order matters in redirections. Bash processes them from left to right. Treat a pipeline as a data interface: each stage should emit a predictable format and report failures clearly.
Exit status is control flow
Every command returns an exit status. Zero means success. A nonzero value means failure. Bash conditionals test this status directly.
if test -r config.ini; then
printf '%s\n' 'Configuration is readable'
else
printf '%s\n' 'Configuration is missing or unreadable' >&2
fi
You do not need to compare the status with zero inside if. Bash runs the command and selects a branch from its result.
By default, a pipeline reports the status of its last command. The pipefail option changes this behavior so an earlier failure can make the pipeline fail. Error handling needs deliberate design because no single shell option replaces checking expected failures and reporting useful context.
Variables, parameters, and arrays
A shell variable stores a value in the current shell. An environment variable is exported so subsequently executed commands receive it.
mode=development
export APP_MODE="$mode"
Do not put spaces around the equals sign in an assignment. Use braces when they make a parameter boundary clear.
archive="${project}_backup.tar"
Scripts receive arguments as positional parameters. "$@" expands each argument as a separate word, which preserves the caller's argument boundaries.
Bash also provides indexed and associative arrays. These are Bash features, not portable POSIX shell syntax.
Interactive shell versus script
An interactive Bash session supports command-line editing, history, job control, aliases, and startup files. A script runs non-interactively from a file or string.
The distinction affects behavior. An interactive non-login shell normally reads ~/.bashrc. A script does not normally read that file. Keep automation self-contained instead of depending on aliases or interactive configuration.
A script commonly begins with an interpreter line:
#!/usr/bin/env bash
The operating system uses this line when the executable file is invoked directly. You can also run a script explicitly with bash script-name.
Where Bash fits
Bash works well for coordinating command-line tools, preparing environments, handling files, and writing small system automation. It is especially useful when the work already consists mainly of processes, arguments, files, and text streams.
Bash is a weaker fit for large data structures, complex application logic, strict type guarantees, or extensive concurrency. In those cases, use Bash as a thin launcher and move the main logic into a language with stronger data and testing support.
Portability is another design choice. A script that needs Bash arrays, [[ ... ]], or other Bash features should declare Bash as its interpreter. A script intended for a POSIX shell should avoid Bash-only features and be tested with the target shell.
A path from first command to reliable automation
- Learn tokens, quoting, expansions, redirections, and exit status.
- Practice pipelines and inspect the status of every stage.
- Write small scripts with explicit inputs and useful error messages.
- Add conditionals, loops, functions, and arrays only when they clarify the work.
- Test scripts with unusual filenames, empty values, failed commands, and interrupted execution.
- Study Bash's compatibility and startup rules before writing portable or environment-sensitive automation.
- Consult the reference manual whenever exact evaluation order or option behavior matters.
