Shell (Bash)
Updated: May 21, 2026Categories: DevOps, Linux, Command Line
Printed from:
Bash Cheatsheet
Language Overview
Bash (Bourne Again SHell) is a powerful Unix shell and command language used for:
- Automating system tasks
- Writing shell scripts
- Interacting with operating systems
- System administration and DevOps
The current stable release is Bash 5.2 (with 5.3 in active development). Bash 5.x introduced features such as the ${var@operator} transformation syntax, the BASH_ARGV0 variable, the EPOCHSECONDS/EPOCHREALTIME variables, and improved associative array handling.
Basic Syntax
Script Structure
Bash
12345678910#!/usr/bin/env bash # Portable shebang line
# This is a comment
# Recommended strict-mode prologue
set -euo pipefail
IFS=$'\n\t'
# Basic script example
echo "Hello, World!"
Command Execution
Bash
123456789# Running commands
command [options] [arguments]
# Example
ls -la /home/user
# Command substitution (prefer $(...) over backticks)
today="$(date +%F)"
Data Types
Primitive Types
- Strings: Text data (default type)
- Integers: Whole numbers (declared with
declare -ifor arithmetic context) - Booleans: Represented by exit codes (0 = true, non-zero = false)
- Arrays: Indexed and associative (associative requires Bash 4+)
Type Examples
Bash
12345678910111213# Strings
name="John Doe"
greeting='Hello, world!'
# Integers
declare -i age=30
count=$((10 + 5))
# Boolean equivalents
if command; then
echo "Command succeeded"
fi
Variables and Constants
Variable Declaration
Bash
1234567891011121314151617# Local variables (inside functions)
local local_var="local value"
# Global variables
GLOBAL_VAR="global value"
# Read-only (constant)
readonly CONSTANT_VAR="cannot be changed"
declare -r ALSO_CONSTANT="another way"
# Environment variables
export PATH="$PATH:/new/path"
# Name references (Bash 4.3+)
declare -n ref=GLOBAL_VAR
echo "$ref"
Parameter Expansion
Bash
123456789101112131415161718192021222324252627# Default values
name="${USER:-Anonymous}"
# Assign default if unset
: "${LOG_DIR:=/var/log/myapp}"
# Substring extraction
string="Hello, World!"
echo "${string:0:5}" # Outputs: Hello
# Length of string
echo "$" # Outputs: 13
# Replace substring
echo "${string/World/Bash}"
echo "${string//l/L}" # Replace all occurrences
# Case modification (Bash 4+)
echo "${string^^}" # Uppercase
echo "${string,,}" # Lowercase
# Transformations (Bash 5.1+)
echo "${string@Q}" # Quoted form, safe to re-evaluate
echo "${string@E}" # Expand escapes
echo "${string@U}" # Uppercase (alternative)
echo "${PATH@a}" # Show variable attributes
Operators
Arithmetic Operators
Bash
1234567891011121314# Basic arithmetic
a=10
b=20
echo $((a + b)) # Addition
echo $((a - b)) # Subtraction
echo $((a * b)) # Multiplication
echo $((b / a)) # Division
echo $((b % a)) # Modulus
echo $((a ** 2)) # Exponentiation
# Arithmetic evaluation context
((counter++))
((total += value))
Comparison Operators
Bash
12345678910111213141516# Numeric comparisons
[[ 10 -eq 10 ]] # Equal
[[ 10 -ne 20 ]] # Not equal
[[ 10 -lt 20 ]] # Less than
[[ 10 -le 20 ]] # Less than or equal
[[ 20 -gt 10 ]] # Greater than
[[ 20 -ge 10 ]] # Greater than or equal
# String comparisons (prefer [[ ]] over [ ])
[[ "$str1" == "$str2" ]] # Equal
[[ "$str1" != "$str2" ]] # Not equal
[[ -z "$str" ]] # Zero length
[[ -n "$str" ]] # Non-zero length
[[ "$str" == prefix* ]] # Pattern matching
[[ "$str" =~ ^[0-9]+$ ]] # Regex matching
Control Structures
Conditional Statements
Bash
12345678910111213141516171819# If-Else (prefer [[ ]] in Bash scripts)
if [[ condition ]]; then
# commands
elif [[ another_condition ]]; then
# commands
else
# commands
fi
# Case statement
case "$value" in
start|begin) echo "Starting" ;;
stop) echo "Stopping" ;;
*) echo "Unknown" ;;
esac
# Compact if (use with care — second command runs if first fails)
[[ condition ]] && command1 || command2
Loops
Bash
123456789101112131415161718192021222324252627282930# For loop
for item in {1..5}; do
echo "$item"
done
# Iterate over array safely
for item in "${fruits[@]}"; do
echo "$item"
done
# C-style for loop
for ((i=0; i<5; i++)); do
echo "$i"
done
# While loop
while [[ condition ]]; do
# commands
done
# Read file line-by-line (safe pattern)
while IFS= read -r line; do
echo "$line"
done < input.txt
# Until loop
until [[ condition ]]; do
# commands
done
Loop Control
Bash
1234567891011# Break and continue
for i in {1..10}; do
if [[ $i -eq 5 ]]; then
break # Exit loop
fi
if [[ $i -eq 3 ]]; then
continue # Skip iteration
fi
echo "$i"
done
Functions
Function Definition
Bash
123456789101112131415161718192021222324# Basic function
greet() {
echo "Hello, $1!"
}
greet "World"
# Function returning an exit status
is_even() {
(( $1 % 2 == 0 ))
}
if is_even 4; then echo "even"; fi
# Function returning data via stdout
add() {
echo $(( $1 + $2 ))
}
result="$(add 5 3)"
# Function with local variables
calculate() {
local result=$(( $1 * $2 ))
echo "$result"
}
Arrays
Indexed Arrays
Bash
1234567891011121314151617# Declaration
fruits=("apple" "banana" "cherry")
declare -a more_fruits
# Access elements
echo "${fruits[0]}" # First element
echo "${fruits[@]}" # All elements (quoted, preserves whitespace)
echo "$" # Array length
echo "${!fruits[@]}" # All indices
# Modifying arrays
fruits+=("date") # Append
unset 'fruits[1]' # Remove element (note quoting)
# Slicing
echo "${fruits[@]:1:2}" # Two elements starting at index 1
Associative Arrays
Bash
123456789101112# Declare associative array (requires Bash 4+)
declare -A person=(
[name]="John"
[age]=30
[city]="New York"
)
# Access
echo "${person[name]}"
echo "${!person[@]}" # All keys
echo "${person[@]}" # All values
Input/Output
Redirection
Bash
1234567891011121314151617181920# Output redirection
echo "Hello" > file.txt # Overwrite
echo "World" >> file.txt # Append
# Input redirection
sort < input.txt > sorted.txt
# Error redirection
command 2> error.log
command > out.log 2>&1 # Redirect stderr to stdout
command &> combined.log # Bash shorthand for both streams
# Here-documents and here-strings
cat <<EOF
multi-line
content
EOF
grep "pattern" <<< "$variable"
# Process substitution
diff <(sort file1) <(sort file2)
Piping
Bash
123456# Pipe output between commands
cat file.txt | grep "pattern" | sort
# Pipe with strict-mode pipefail catches mid-pipeline failures
set -o pipefail
Text Processing
Basic Tools
Bash
123456789101112# Grep (search)
grep -E "pattern" file.txt
grep -rn "needle" .
# Sed (stream editor)
sed 's/old/new/g' file.txt
sed -i.bak 's/old/new/g' file.txt # In-place with backup
# Awk (text processing)
awk '{print $1}' file.txt
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
Process Management
Bash
1234567891011121314151617# Background jobs
command & # Run in background
jobs # List background jobs
fg %1 # Bring job to foreground
wait # Wait for all background jobs
wait "$pid" # Wait for a specific PID
# Process control
ps aux # List processes
kill "$PID" # Terminate process
kill -TERM "$PID" # Send specific signal
killall process_name # Kill all processes with name
# Trap signals for cleanup
cleanup() { rm -f "$tmpfile"; }
trap cleanup EXIT INT TERM
Environment and Configuration
Bash
123456789101112# Environment variables
printenv # Show all variables
export VARNAME=value # Set environment variable
# Useful Bash 5.x built-in variables
echo "$EPOCHSECONDS" # Unix timestamp without forking
echo "$EPOCHREALTIME" # High-resolution timestamp
echo "$BASH_VERSION"
# Shell configuration
source ~/.bashrc # Reload configuration
Error Handling
Bash
1234567891011121314151617# Strict-mode prologue
set -euo pipefail
IFS=$'\n\t'
# Exit codes
command
echo $? # Check exit status (0 = success)
# Error checking
if ! command; then
echo "Command failed" >&2
exit 1
fi
# ERR trap for centralized error reporting
trap 'echo "Error on line $LINENO" >&2' ERR
File Operations
Bash
12345678910111213141516171819# File tests (prefer [[ ]])
[[ -e path ]] # Exists (file, dir, link, etc.)
[[ -f file.txt ]] # Regular file exists
[[ -d directory ]] # Directory exists
[[ -L link ]] # Symbolic link
[[ -r file ]] # File is readable
[[ -w file ]] # File is writable
[[ -x file ]] # File is executable
[[ -s file ]] # File exists and is non-empty
[[ file1 -nt file2 ]] # file1 newer than file2
# Permissions
chmod 755 script.sh # Change file permissions
chown user:group file # Change ownership
# Safe temporary files
tmpfile="$(mktemp)"
trap 'rm -f "$tmpfile"' EXIT
Best Practices
- Start scripts with
#!/usr/bin/env bashandset -euo pipefail - Always quote variable expansions:
"$var","${array[@]}" - Prefer
[[ ... ]]over[ ... ]and$(...)over backticks - Use
localfor all variables inside functions - Run
shellcheckandshfmtin CI for static analysis and formatting - Avoid parsing the output of
ls; use globs orfind -print0withread -d '' - Use
mktempfor temporary files and clean them up withtrap - Prefer Bash built-ins (parameter expansion,
[[ ]]) over external tools when possible
Testing Shell Scripts
- Use
bats-core(the actively maintained successor to the originalbats) - Companion libraries:
bats-assert,bats-support,bats-file - Mock external commands by overriding
PATHor defining shim functions - Test edge cases, error paths, and exit codes explicitly
- Lint with
shellcheckand format withshfmtas part of CI
Security Considerations
- Validate and sanitize all external input
- Use
--to terminate option processing before user-supplied arguments - Avoid
eval; if unavoidable, restrict and escape inputs with${var@Q} - Quote every expansion to prevent word splitting and globbing
- Limit use of
sudoand prefer least-privilege execution - Use
read -rsfor sensitive inputs (raw mode, silent) - Be wary of command injection in
$(...), backticks, and indirect expansion
Deprecated / Discouraged Patterns
- Backticks
`cmd`→ use$(cmd) - Single-bracket
[ ... ]for new scripts → prefer[[ ... ]]in Bash function name() { ... }mixed syntax → usename() { ... }exprfor arithmetic → use$(( ... ))or(( ... ))- Parsing
lsoutput → use globs,find, orprintf '%s\0' #!/bin/shwhen relying on Bash features → use#!/usr/bin/env bash
Resources for Further Learning
- GNU Bash Manual (official documentation)
- Bash Reference Manual (gnu.org)
- ShellCheck (linting tool) and shfmt (formatter)
- BashGuide on the Greg's Wiki (mywiki.wooledge.org)
- Bash Hackers Wiki (community-maintained archive)
- "Pro Bash Programming" and the Advanced Bash-Scripting Guide (use critically; some content is dated)
Conclusion
Bash remains the de facto standard scripting shell on most Linux distributions and a key tool for DevOps, automation, and system administration. Embrace strict mode, quote rigorously, lint with ShellCheck, and prefer modern Bash idioms to write scripts that are safe, portable, and maintainable.
Continue Learning
Discover more cheatsheets to boost your productivity