Robin.te.Hofstee

Bash Scripting Cheatsheet

Robin te Hofstee17 min readViews0
Bash Scripting Cheatsheet

A comprehensive Bash scripting reference guide covering variables, loops, functions, conditionals, arrays, and more. Quick reference for all your shell scripting needs.

Bash Scripting Cheatsheet

Getting Started

Introduction

This is a comprehensive quick reference to Bash scripting. Bash is a Unix shell and command language that provides a powerful interface for interacting with your operating system.

Useful Resources:

Hello World Example

#!/usr/bin/env bash
 
name="John"
echo "Hello $name!"

Variables

name="John"
echo $name       # John
echo "$name"     # John (recommended)
echo "${name}!"  # John!

Best Practice: Generally quote your variables unless they contain wildcards to expand or command fragments.

wildcard="*.txt"
options="iv"
cp -$options $wildcard /tmp

String Quotes

name="John"
echo "Hi $name"  # Hi John (variables expand)
echo 'Hi $name'  # Hi $name (no expansion)

Shell Execution

echo "I'm in $(pwd)"
echo "I'm in `pwd`"  # obsolescent syntax
# Both produce the same output

Conditional Execution

git commit && git push           # Run push only if commit succeeds
git commit || echo "Commit failed"  # Run echo only if commit fails

Strict Mode

Enable strict mode for safer scripts:

set -euo pipefail
IFS=$'\n\t'

This enables:

  • errexit: Exit on error
  • nounset: Error on unset variables
  • pipefail: Catch errors in pipes

Brace Expansion

echo {A,B}.js        # A.js B.js
echo {1..5}          # 1 2 3 4 5
echo {{1..3},{7..9}} # 1 2 3 7 8 9
ExpressionDescriptionOutput
{A,B}Expand alternativesA B
{A,B}.jsWith suffixA.js B.js
{1..5}Numeric range1 2 3 4 5
{1..10..2}Range with step1 3 5 7 9

Parameter Expansions

Basic Expansions

name="John"
echo "${name}"           # John
echo "${name/J/j}"       # john (substitution)
echo "${name:0:2}"       # Jo (slicing)
echo "${name::2}"        # Jo (slicing)
echo "${name::-1}"       # Joh (remove last char)
echo "${name:(-1)}"      # n (last char)
echo "${name:(-2):1}"    # h (second to last char)
echo "${food:-Cake}"     # $food or "Cake" if unset

String Manipulation

str="/path/to/foo.cpp"
 
# Remove suffix
echo "${str%.cpp}"       # /path/to/foo
echo "${str%.cpp}.o"     # /path/to/foo.o
echo "${str%/*}"         # /path/to
 
# Extract extension and basename
echo "${str##*.}"        # cpp
echo "${str##*/}"        # foo.cpp
 
# Remove prefix
echo "${str#*/}"         # path/to/foo.cpp
echo "${str##*/}"        # foo.cpp
 
# Replace
echo "${str/foo/bar}"    # /path/to/bar.cpp

Slicing

str="Hello world"
echo "${str:6:5}"        # world
echo "${str: -5:5}"      # world (from end)

Path Manipulation

src="/path/to/foo.cpp"
base=${src##*/}          # foo.cpp (basename)
dir=${src%$base}         # /path/to/ (directory path)
dir=${src%/*}            # /path/to (directory)

Substitution Reference

CodeDescription
${foo%suffix}Remove shortest suffix
${foo%%suffix}Remove longest suffix
${foo#prefix}Remove shortest prefix
${foo##prefix}Remove longest prefix
${foo/from/to}Replace first match
${foo//from/to}Replace all matches
${foo/%from/to}Replace suffix
${foo/#from/to}Replace prefix

Length

str="Hello"
echo "${#str}"           # 5 (string length)

Case Modification

str="HELLO WORLD!"
echo "${str,}"           # hELLO WORLD! (lowercase first)
echo "${str,,}"          # hello world! (all lowercase)
 
str="hello world!"
echo "${str^}"           # Hello world! (uppercase first)
echo "${str^^}"          # HELLO WORLD! (all uppercase)

Default Values

ExpressionDescription
${foo:-val}$foo, or val if unset/null
${foo:=val}Set $foo to val if unset/null
${foo:+val}val if $foo is set
${foo:?message}Show error and exit if unset/null

Comments

# Single line comment
 
: '
This is a
multi-line
comment
'

Loops

Basic For Loop

for i in /etc/rc.*; do
  echo "$i"
done

C-style For Loop

for ((i = 0; i < 100; i++)); do
  echo "$i"
done

Ranges

for i in {1..5}; do
  echo "Welcome $i"
done

With Step Size

for i in {5..50..5}; do
  echo "Welcome $i"
done

Reading Lines

while read -r line; do
  echo "$line"
done < file.txt

Infinite Loop

while true; do
  # Your code here
  sleep 1
done

Until Loop

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

Functions

Defining Functions

# Method 1
myfunc() {
  echo "hello $1"
}
 
# Method 2
function myfunc {
  echo "hello $1"
}
 
# Call the function
myfunc "John"

Returning Values

myfunc() {
  local myresult='some value'
  echo "$myresult"
}
 
result=$(myfunc)
echo "$result"

Return Status

myfunc() {
  return 1  # Return exit code
}
 
if myfunc; then
  echo "success"
else
  echo "failure"
fi

Function Arguments

ExpressionDescription
$#Number of arguments
$*All positional arguments (as single word)
$@All positional arguments (as separate strings)
$1First argument
$_Last argument of previous command

Note: $@ and $* must be quoted to preserve behavior.


Conditionals

String Conditions

ConditionDescription
[[ -z STRING ]]Empty string
[[ -n STRING ]]Not empty string
[[ STRING == STRING ]]Equal
[[ STRING != STRING ]]Not equal
[[ STRING =~ REGEX ]]Regex match

Numeric Conditions

ConditionDescription
[[ NUM -eq NUM ]]Equal
[[ NUM -ne NUM ]]Not equal
[[ NUM -lt NUM ]]Less than
[[ NUM -le NUM ]]Less than or equal
[[ NUM -gt NUM ]]Greater than
[[ NUM -ge NUM ]]Greater than or equal
(( NUM < NUM ))Numeric comparison

File Conditions

ConditionDescription
[[ -e FILE ]]Exists
[[ -f FILE ]]Regular file
[[ -d FILE ]]Directory
[[ -h FILE ]]Symlink
[[ -r FILE ]]Readable
[[ -w FILE ]]Writable
[[ -x FILE ]]Executable
[[ -s FILE ]]Size is > 0 bytes
[[ FILE1 -nt FILE2 ]]FILE1 is newer than FILE2
[[ FILE1 -ot FILE2 ]]FILE1 is older than FILE2
[[ FILE1 -ef FILE2 ]]Same files

Logical Operators

ConditionDescription
[[ ! EXPR ]]Not
[[ X && Y ]]And
`[[ X

If Statement Examples

# String check
if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
fi
 
# Combinations
if [[ X && Y ]]; then
  echo "Both true"
fi
 
# Numeric comparison
if (( $a < $b )); then
  echo "$a is smaller than $b"
fi
 
# File exists
if [[ -e "file.txt" ]]; then
  echo "file exists"
fi
 
# Regex
if [[ "$email" =~ ^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$ ]]; then
  echo "Valid email"
fi

Arrays

Defining Arrays

# Method 1
Fruits=('Apple' 'Banana' 'Orange')
 
# Method 2
Fruits[0]="Apple"
Fruits[1]="Banana"
Fruits[2]="Orange"

Accessing Arrays

echo "${Fruits[0]}"           # Element #0
echo "${Fruits[-1]}"          # Last element
echo "${Fruits[@]}"           # All elements
echo "${#Fruits[@]}"          # Number of elements
echo "${#Fruits}"             # String length of 1st element
echo "${#Fruits[3]}"          # String length of Nth element
echo "${Fruits[@]:3:2}"       # Range (from position 3, length 2)
echo "${!Fruits[@]}"          # All indices

Array Operations

# Append
Fruits=("${Fruits[@]}" "Watermelon")
Fruits+=('Watermelon')
 
# Remove by regex
Fruits=( "${Fruits[@]/Ap*/}" )
 
# Remove one item
unset Fruits[2]
 
# Duplicate
Fruits=("${Fruits[@]}")
 
# Concatenate
Fruits=("${Fruits[@]}" "${Veggies[@]}")
 
# Read from file
lines=($(< file.txt))

Iteration

for i in "${arrayName[@]}"; do
  echo "$i"
done

Dictionaries (Associative Arrays)

Defining Dictionaries

declare -A sounds
 
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"

Working with Dictionaries

echo "${sounds[dog]}"     # Dog's sound
echo "${sounds[@]}"       # All values
echo "${!sounds[@]}"      # All keys
echo "${#sounds[@]}"      # Number of elements
unset sounds[dog]         # Delete dog

Iteration

# Iterate over values
for val in "${sounds[@]}"; do
  echo "$val"
done
 
# Iterate over keys
for key in "${!sounds[@]}"; do
  echo "$key - ${sounds[$key]}"
done

Options and Settings

Set Options

set -o noclobber   # Prevent file overwrite with >
set -o errexit     # Exit on error
set -o pipefail    # Catch errors in pipes
set -o nounset     # Error on unset variables

Shopt Options

shopt -s nullglob     # Non-matching globs expand to nothing
shopt -s failglob     # Non-matching globs throw errors
shopt -s nocaseglob   # Case insensitive globs
shopt -s dotglob      # Match hidden files with *
shopt -s globstar     # Enable ** for recursive matching

History

History Commands

CommandDescription
historyShow command history
shopt -s histverifyDon't execute expanded result immediately

History Expansions

ExpressionDescription
!!Last command
!$Last argument of last command
!*All arguments of last command
!-nnth most recent command
!nnth command in history
!stringMost recent command starting with string

History Operations

CodeDescription
!!:s/FROM/TO/Replace first occurrence
!!:gs/FROM/TO/Replace all occurrences
!$:tBasename of last argument
!$:hDirectory of last argument

Input/Output Redirection

Basic Redirection

# Redirect stdout to file
command > output.txt
 
# Append stdout to file
command >> output.txt
 
# Redirect stderr to file
command 2> error.log
 
# Redirect stderr to stdout
command 2>&1
 
# Redirect both stdout and stderr
command &> output.txt
command > output.txt 2>&1
 
# Redirect to null (discard)
command > /dev/null
command 2> /dev/null
command &> /dev/null
 
# Read from file
command < input.txt

Advanced Redirection

# Compare two outputs
diff <(ls dir1) <(ls dir2)
 
# Process substitution
while read -r line; do
  echo "$line"
done < <(command)

Heredoc

cat <<EOF
This is a
multi-line
text block
EOF

Herestring

tr '[:lower:]' '[:upper:]' <<< "hello world"
# Output: HELLO WORLD

Miscellaneous

Arithmetic

# Addition
echo $((a + 200))
 
# Random number
echo $((RANDOM % 200))  # 0-199
 
# Increment
count=$((count + 1))
((count++))
 
# Declare integer
declare -i count
count+=1

Case Statement

case "$1" in
  start | up)
    echo "Starting..."
    ;;
  stop | down)
    echo "Stopping..."
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac

Printf

printf "Hello %s, I'm %s\n" Sven Olga
# Output: Hello Sven, I'm Olga
 
printf "Number: %d\n" 42
# Output: Number: 42
 
printf "Float: %.2f\n" 3.14159
# Output: Float: 3.14

Reading Input

# Read with prompt
echo -n "Proceed? [y/n]: "
read -r ans
echo "$ans"
 
# Read single character
read -n 1 ans
 
# Read with timeout
read -t 5 ans  # 5 second timeout
 
# Read password (hidden)
read -s password

Special Variables

VariableDescription
$?Exit status of last command
$!PID of last background task
$$PID of current shell
$0Name of the script
$1 to $9Script arguments
$#Number of arguments
$@All arguments (as separate words)
$*All arguments (as single word)
$_Last argument of previous command
${PIPESTATUS[@]}Exit status of each piped command

Subshells

# Execute in subshell (doesn't affect current directory)
(cd somedir; echo "I'm now in $PWD")
pwd  # Still in original directory

Error Trapping

# Simple error trap
trap 'echo "Error at line $LINENO"' ERR
 
# Advanced error trap
traperr() {
  echo "ERROR: ${BASH_SOURCE[1]} at line ${BASH_LINENO[0]}"
}
 
set -o errtrace
trap traperr ERR

Command Substitution

# Modern syntax (recommended)
result=$(command)
 
# Old syntax (avoid)
result=`command`

Process Substitution

# Compare outputs
diff <(ls dir1) <(ls dir2)
 
# Loop through command output
while read -r line; do
  echo "$line"
done < <(find . -name "*.txt")

String Transformations with tr

# Convert to uppercase
echo "hello" | tr '[:lower:]' '[:upper:]'
 
# Delete characters
echo "hello123world" | tr -d '[:digit:]'
 
# Squeeze repeated characters
echo "hellooo   world" | tr -s 'o '

Checking Commands

# Check if command succeeded
if ping -c 1 google.com &> /dev/null; then
  echo "Internet connection available"
fi
 
# Check if string in file
if grep -q 'pattern' file.txt; then
  echo "Pattern found"
fi
 
# Check if command exists
if command -v git &> /dev/null; then
  echo "Git is installed"
fi

Directory Navigation

# Go to previous directory
cd -
 
# Go to home directory
cd ~
cd
 
# Go to directory of script
cd "$(dirname "$0")"

Best Practices

Script Template

#!/usr/bin/env bash
 
# Exit on error, undefined variables, and pipe failures
set -euo pipefail
 
# Set IFS for safer word splitting
IFS=$'\n\t'
 
# Script description
# Usage: ./script.sh [options]
 
# Functions
main() {
  # Your main logic here
  echo "Hello, World!"
}
 
# Run main function
main "$@"

Debugging

# Enable debug mode
set -x
 
# Debug a specific section
set -x
# code to debug
set +x
 
# Run with debug
bash -x script.sh

Error Handling

# Check if file exists before reading
if [[ ! -f "$filename" ]]; then
  echo "Error: File not found: $filename" >&2
  exit 1
fi
 
# Validate number of arguments
if [[ $# -ne 2 ]]; then
  echo "Usage: $0 <arg1> <arg2>" >&2
  exit 1
fi

Useful One-Liners

# Find and delete files
find . -name "*.tmp" -delete
 
# Archive and compress
tar -czf archive.tar.gz directory/
 
# Extract archive
tar -xzf archive.tar.gz
 
# Find large files
find . -type f -size +100M
 
# Monitor file changes
watch -n 1 'ls -lh file.txt'
 
# Quick HTTP server
python3 -m http.server 8000
 
# Count lines of code
find . -name '*.sh' | xargs wc -l
 
# Replace in multiple files
find . -name "*.txt" -exec sed -i 's/old/new/g' {} +

Additional Resources


Happy Scripting! 🚀

Share this post
Robin te Hofstee

Written by Robin te Hofstee

Technology enthusiast with a deep love for programming. Sharing practical guides on React, Next.js, Linux and self-hosting.

How Git Works

1

Git is a distributed version control system that allows multiple people to collaborate on a project while maintaining a complete history of all change