Tutorial Bash Shell Scripting Linux Developer Tools Cheat Sheet

Free Bash Scripting Cheat Sheet Online — Interactive Shell Script Reference

· 18 min read

Bash is the default shell on nearly every Linux distribution and macOS. It powers deployment pipelines, system maintenance scripts, development workflows, and automated testing. Every developer who works with servers, containers, or CI/CD systems eventually needs to write or read a shell script. Yet bash syntax is famously tricky — the difference between $var and "$var" can introduce spaces-in-filenames bugs that break production deployments. The rules for parameter expansion, the behavior of unquoted variables, and the subtle differences between [ ] and [[ ]] catch even experienced developers off guard.

Our free interactive bash scripting cheat sheet provides eighty-plus copyable commands and syntax examples organized into twelve categories: variables and parameters, conditionals, loops, functions, string manipulation, arrays, redirection and pipes, file test operators, arithmetic operations, exit codes and error handling, and useful one-liners. The Blacksmith's Forge aesthetic — deep charcoal background with molten amber accents, floating ember particles, and forged-iron typography — transforms script reference into craft. Everything runs in your browser. No server, no signup, no data collection.

Why Bash Scripting Still Matters

Despite the rise of Python, Go, and JavaScript for automation, bash remains the universal glue of Unix-like systems. It is the only language guaranteed to exist on every Linux server, every Docker container, and every CI/CD runner. A twenty-line bash script can install dependencies, configure services, rotate logs, and send alerts — tasks that would require hundreds of lines and multiple dependencies in most other languages.

Bash scripting is not going away. Kubernetes init containers run shell commands. GitHub Actions workflows execute bash scripts. Docker ENTRYPOINT scripts bootstrap containers. Cloud-init scripts configure new VM instances. The ability to read and write bash is a fundamental skill for anyone who touches a Unix-like system.

Yet bash is also a minefield of footguns. Word splitting, globbing, and exit code handling behave in ways that surprise programmers coming from other languages. A well-organized cheat sheet provides three benefits: it surfaces the correct syntax for common patterns, it warns about dangerous defaults, and it provides copyable snippets that follow best practices.

Variables and Parameters

Bash variables are strings by default. No type declarations are required, but this flexibility comes with pitfalls — unquoted variables undergo word splitting and pathname expansion, which is the root cause of countless script bugs.

Variable Assignment

Assignment uses = with no spaces around it. Quoting the right-hand side prevents word splitting but is not always necessary for simple values.

name="John Doe"
age=30
readonly PI=3.14159      # cannot be changed
declare -r MAX=100       # same as readonly

Variable Reference

Use $var or ${var} to access values. The braces form is safer because it disambiguates variable names from adjacent text. Always quote variables when passing them as arguments to avoid word splitting.

echo "Hello, $name"
echo "Hello, ${name}"    # safer, allows concatenation
echo "${name:-default}"  # use default if unset
echo "${name:=default}"  # set and use default if unset

Environment Variables

Variables are local to the current shell unless exported. Child processes inherit exported variables but cannot modify the parent's environment.

export PATH="/usr/local/bin:$PATH"
export API_KEY="secret123"
env                      # list all environment variables
printenv HOME            # print specific env variable
unset API_KEY            # remove variable

Special Variables

Bash provides built-in variables for script arguments, process IDs, and exit codes. These are essential for writing reusable scripts.

$0       # script name
$1 $2 ... # positional parameters
$#       # number of arguments
$*       # all args as single word
$@       # all args as separate words (always quote this)
$?       # exit status of last command
$$       # PID of current shell
$!       # PID of last background command
$_       # last argument of previous command

Parameter Expansion

Parameter expansion is one of bash's most powerful and underutilized features. It provides default values, substring extraction, pattern replacement, and length calculation without spawning external processes.

${var:-default}      # default if unset/null
${var:=default}      # assign default if unset/null
${var:?message}      # error and exit if unset/null
${var:+replacement}  # replacement if set/non-null
${#var}              # length of variable
${var:offset}        # substring from offset
${var:offset:length} # substring with length
${var#pattern}       # remove shortest prefix match
${var##pattern}      # remove longest prefix match
${var%pattern}       # remove shortest suffix match
${var%%pattern}      # remove longest suffix match
${var/pattern/repl}  # replace first match
${var//pattern/repl} # replace all matches

Conditionals

Bash provides if, case, and the test command for conditional execution. The [[ ]] construct is preferred over [ ] for string comparisons because it supports pattern matching and regex without quoting complications.

if Statement

The basic conditional structure supports if, elif, and else branches. The then keyword must follow the condition on the same line or on the next line.

if [ $age -gt 18 ]; then
    echo "Adult"
elif [ $age -eq 18 ]; then
    echo "Just turned adult"
else
    echo "Minor"
fi

# One-liner using && and ||
[ $x -eq 1 ] && echo "yes" || echo "no"

Test Operators — Numeric

Integer comparisons use -eq, -ne, -lt, -le, -gt, and -ge. Inside (( )) arithmetic context, you can use C-style operators.

[ $a -eq $b ]   # equal
[ $a -ne $b ]   # not equal
[ $a -lt $b ]   # less than
[ $a -le $b ]   # less than or equal
[ $a -gt $b ]   # greater than
[ $a -ge $b ]   # greater than or equal

# In (( )) you can use familiar operators:
(( a == b ))
(( a > b ))

Test Operators — Strings

String tests check for emptiness, equality, and pattern matching. Always quote string variables in test expressions.

[ "$str" ]         # non-empty string
[ -z "$str" ]      # zero length / empty
[ -n "$str" ]      # non-zero length
[ "$a" = "$b" ]    # strings equal
[ "$a" != "$b" ]   # strings not equal
[[ "$a" == "x*" ]] # pattern match in [[ ]]
[[ "$a" =~ regex ]] # regex match (bash 3.0+)

case Statement

case provides pattern matching for multiple conditions. It is cleaner than a chain of if/elif when comparing a single value against multiple patterns. Patterns support glob-style wildcards and the | alternation operator.

case $os in
    Linux|linux|GNU)
        echo "Linux system"
        ;;
    Darwin)
        echo "macOS system"
        ;;
    CYGWIN|MINGW|MSYS)
        echo "Windows subsystem"
        ;;
    *)
        echo "Unknown: $os"
        ;;
esac

Logical Operators

Conditions can be combined with && (AND), || (OR), and ! (NOT). Inside [[ ]], these operators can be used directly within the brackets.

[ $a -eq 1 ] && [ $b -eq 2 ]    # AND
[ $a -eq 1 ] || [ $b -eq 2 ]    # OR
! [ $a -eq 1 ]                    # NOT

[[ $a == "x" && $b == "y" ]]
[[ $a == "x" || $b == "y" ]]

Loops

Bash provides three loop constructs: for for iterating over lists, while for conditional repetition, and until for looping until a condition becomes true.

for Loop — List

The for loop iterates over a whitespace-separated list of words. For lists that might contain spaces, use arrays or quote appropriately.

for item in apple banana cherry; do
    echo "Fruit: $item"
done

# C-style for loop (bash extension)
for (( i=0; i<10; i++ )); do
    echo "Iteration $i"
done

for Loop — Files

Iterating over files is one of the most common loop use cases. The glob pattern expands to matching filenames before the loop runs.

for file in *.txt; do
    echo "Processing $file"
done

# Recursive iteration with find
while IFS= read -r -d '' file; do
    echo "Found: $file"
done < <(find . -name "*.sh" -print0)

while Loop

The while loop executes as long as its condition is true. It is ideal for reading files line by line and for counter-based loops.

count=0
while [ $count -lt 5 ]; do
    echo "Count: $count"
    ((count++))
done

# Read file line by line
while IFS= read -r line; do
    echo "Line: $line"
done < file.txt

until Loop

The until loop is the inverse of while — it executes until its condition becomes true. It is useful for waiting operations and retry logic.

count=0
until [ $count -ge 5 ]; do
    echo "Count: $count"
    ((count++))
done

Loop Control

break exits the loop entirely. continue skips to the next iteration. Both accept an optional numeric argument to break or continue out of nested loops.

for i in {1..10}; do
    [ $i -eq 3 ] && continue   # skip iteration 3
    [ $i -eq 7 ] && break      # exit loop at 7
    echo $i
done

Functions

Bash functions group reusable code blocks. They can accept arguments, return exit codes, and capture output into variables. Local variables prevent functions from polluting the global namespace.

Function Definition

Functions can be defined with the function keyword or without it. Both styles are equivalent in bash.

# Style 1
function greet() {
    local name=$1          # local variable
    echo "Hello, $name!"
}

# Style 2 (no keyword)
greet() {
    echo "Hello, $1!"
}

# Call
greet "World"              # output: Hello, World!
result=$(greet "World")    # capture output

Return Values

Bash functions can only return integer exit codes (0-255) via the return statement. To return strings, use echo and command substitution.

# Return exit code (0-255)
is_even() {
    local n=$1
    (( n % 2 == 0 )) && return 0 || return 1
}

# Return string via echo
get_full_name() {
    local first=$1 last=$2
    echo "$first $last"
}
name=$(get_full_name "John" "Doe")

# Check return code
is_even 4 && echo "Even" || echo "Odd"

Function Arguments

Function arguments use the same positional parameter variables as scripts: $1, $2, $#, $@. The shift command removes $1 and shifts remaining arguments left.

process() {
    echo "First: $1"
    echo "Second: $2"
    echo "All: $@"
    echo "Count: $#"
    shift                  # shift args left (removes $1)
    echo "After shift: $1"
}

process one two three

String Manipulation

Bash provides extensive string manipulation through parameter expansion. These operations are fast because they run entirely within the shell without spawning external processes like sed or awk.

String Length and Extraction

str="Hello, World!"

echo "${#str}"             # length: 13
echo "${str:0:5}"          # substring: Hello
echo "${str:7}"            # from index 7: World!
echo "${str: -6}"          # last 6 chars: World!
echo "${str: -6:5}"        # last 6, then 5: World

String Replacement

str="/usr/local/bin:/usr/bin:/bin"

echo "${str/usr/opt}"       # replace first
echo "${str//usr/opt}"      # replace all
echo "${str/#\/usr/\/opt}"  # replace prefix
echo "${str/%\/bin/\/sbin}" # replace suffix
echo "${str//usr/}"         # delete all occurrences

Case Conversion

str="Hello World"

echo "${str^^}"            # uppercase: HELLO WORLD
echo "${str,,}"            # lowercase: hello world
echo "${str~~}"            # swap case: hELLO wORLD
echo "${str^}"             # first char uppercase
echo "${str,}"             # first char lowercase

Trimming

The # and % operators remove prefix and suffix patterns. A single operator removes the shortest match; doubling it removes the longest match.

path="/home/user/file.txt"

echo "${path#*/}"          # remove shortest prefix: home/user/file.txt
echo "${path##*/}"         # remove longest prefix: file.txt
echo "${path%.*}"          # remove shortest suffix: /home/user/file
echo "${path%%.*}"         # remove longest suffix: /home/user/file

Arrays

Bash supports both indexed arrays (ordered lists) and associative arrays (key-value pairs, bash 4.0+). Arrays are the correct way to handle lists of values that might contain spaces.

Indexed Arrays

fruits=(apple banana cherry)
numbers=(10 20 30 40 50)

echo "${fruits[0]}"        # apple (first element)
echo "${fruits[-1]}"       # cherry (last, bash 4.2+)
echo "${#fruits[@]}"       # 3 (array length)
echo "${fruits[@]}"        # all elements
echo "${!fruits[@]}"       # all indices

Array Operations

arr=(a b c)
arr+=(d e)                 # append
arr[3]=f                   # insert at index
unset arr[1]               # remove element
echo "${arr[@]:1:2}"       # slice elements 1-2
IFS=','; echo "${arr[*]}"; unset IFS  # join with delimiter

Associative Arrays

declare -A user

user["name"]="John"
user["email"]="john@example.com"
user["role"]="admin"

echo "${user[name]}"       # access value
echo "${#user[@]}"         # number of keys
echo "${!user[@]}"         # all keys
echo "${user[@]}"          # all values

for key in "${!user[@]}"; do
    echo "$key: ${user[$key]}"
done

Redirection and Pipes

Redirection and pipes are the Unix philosophy in action: small programs connected by streams. Bash provides powerful operators for routing input, output, and errors.

Output Redirection

command > file.txt         # stdout to file (overwrite)
command >> file.txt        # stdout to file (append)
command 2> error.log       # stderr to file
command &> output.log      # stdout and stderr to file
command > /dev/null        # discard stdout
command 2>&1               # redirect stderr to stdout
command > file.txt 2>&1    # both to file

Input Redirection

command < input.txt        # read stdin from file
command << EOF
line1
line2
EOF

command <<< "input string"  # here-string

diff <(sort file1) <(sort file2)  # process substitution

Pipes

cat file.txt | grep "pattern" | sort | uniq | wc -l

echo "data" | tee log.txt | grep "filter"

# Named pipes (FIFO)
mkfifo mypipe
echo "hello" > mypipe &
cat < mypipe

File Test Operators

File tests check the existence, type, and permissions of files and directories. These are essential for writing robust scripts that handle missing files gracefully.

File Existence and Type

[ -e file ]     # exists
[ -f file ]     # regular file
[ -d file ]     # directory
[ -L file ]     # symbolic link
[ -b file ]     # block device
[ -c file ]     # character device
[ -p file ]     # named pipe
[ -S file ]     # socket

File Permissions

[ -r file ]     # readable
[ -w file ]     # writable
[ -x file ]     # executable
[ -s file ]     # size > 0 (non-empty)
[ -O file ]     # owned by effective UID
[ -G file ]     # owned by effective GID

File Comparison

[ file1 -nt file2 ]   # file1 newer than file2
[ file1 -ot file2 ]   # file1 older than file2
[ file1 -ef file2 ]   # same physical file (same inode)

Arithmetic

Bash performs integer arithmetic in $(( )) arithmetic expansion. Floating-point math requires external tools like bc or awk.

Arithmetic Expansion

result=$(( 5 + 3 ))
echo $(( 10 - 4 ))
echo $(( 6 * 7 ))
echo $(( 20 / 3 ))      # integer division: 6
echo $(( 20 % 3 ))      # modulo: 2
echo $(( 2 ** 10 ))     # power: 1024 (bash 4.0+)

((x++))                 # increment
((x--))                 # decrement
((x += 5))              # compound assignment

Bitwise and Logical

echo $(( 5 & 3 ))       # AND: 1
echo $(( 5 | 3 ))       # OR: 7
echo $(( 5 ^ 3 ))       # XOR: 6
echo $(( ~5 ))          # NOT
echo $(( 16 << 2 ))     # left shift: 64
echo $(( 16 >> 2 ))     # right shift: 4

let Command

let x=5+3
let "y = x * 2"
let "a++"
let "b += 10"

if let "x % 2 == 0"; then
    echo "Even"
fi

Exit Codes and Error Handling

Every command returns an exit code: zero for success, non-zero for failure. Scripts that ignore exit codes silently continue past errors, producing confusing and dangerous behavior.

Exit Codes Reference

0    # Success
1    # General error
2    # Misuse of shell builtins
126  # Command invoked cannot execute
127  # Command not found
128+N # Fatal signal N (e.g., 130 = Ctrl+C/SIGINT)
130  # Script terminated by Ctrl+C
137  # Killed with SIGKILL (kill -9)
143  # Killed with SIGTERM

Strict Mode

The set -euo pipefail combination enables strict error handling. -e exits on error, -u exits on undefined variables, and -o pipefail causes pipelines to fail if any command fails.

set -euo pipefail

# Trap signals
trap 'echo "Interrupted"; exit 1' INT TERM

# Cleanup on exit
tempfile=$(mktemp)
trap 'rm -f "$tempfile"' EXIT

Useful One-liners

These single-line commands solve common problems without writing full scripts.

# Read file into array
mapfile -t lines < file.txt

# Default value if variable is empty
name="${1:-default}"

# Check if command exists
command -v git &> /dev/null && echo "git installed"

# Get script directory
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)

# Parallel processing with xargs
cat urls.txt | xargs -P 4 -n 1 curl -s -o /dev/null

Script Template

This template provides a robust starting point for new bash scripts. It includes strict mode, argument parsing, help text, and cleanup handling.

#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
SCRIPT_NAME=$(basename "$0")

usage() {
    cat << EOF
Usage: $SCRIPT_NAME [OPTIONS]

Options:
    -h, --help      Show this help
    -v, --verbose   Enable verbose output
EOF
}

main() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help) usage; exit 0 ;;
            -v|--verbose) VERBOSE=1; shift ;;
            *) echo "Unknown option: $1" >&2; usage; exit 1 ;;
        esac
    done

    echo "Hello, World!"
}

main "$@"

The Interactive Cheat Sheet

Our free interactive bash scripting cheat sheet organizes seventy-plus advanced patterns into eleven categories with real-time search, category filtering, and one-click copy. Each pattern includes syntax highlighting with color-coded keywords, strings, variables, numbers, comments, and operators.

The Submarine Control Room aesthetic uses deep ocean-blue backgrounds, fluorescent cyan and amber accents, a subtle sonar pulse animation, and precision instrument typography. The design reinforces bash scripting as a mission-critical craft — each command calibrated, each script running silent and deep.

Everything is 100% client-side. Your script experiments and command references never leave your browser.

Related Tools and References

Bash scripting interacts with virtually every aspect of system administration and development. These related DevToolkit resources cover adjacent topics:

Bookmark the Bash Scripting Cheat Sheet for instant access whenever you need to write a script, look up syntax, or remember a parameter expansion trick. Whether you are automating deployments, writing system administration tools, or studying for a Linux certification, this reference provides the commands and concepts you need.

Found this useful? Check out our free developer tools or browse more articles.