Shell Scripting Cheatsheet

Table of Contents

  1. Script Basics
  2. Variables
  3. String Operations
  4. Arithmetic
  5. Conditionals
  6. Test Operators
  7. Loops
  8. Functions
  9. Arrays
  10. Input & Arguments
  11. Redirection & Pipes
  12. Exit Codes & Error Handling
  13. String Manipulation
  14. File Operations
  15. Process Control
  16. Docker Entrypoint Patterns
  17. Useful One-Liners

Script Basics

Pattern Description
#!/bin/bash Bash shebang (script header)
#!/bin/sh POSIX shell shebang (more portable)
#!/usr/bin/env bash Portable bash shebang
chmod +x script.sh Make script executable
./script.sh Run script
bash script.sh Run without execute permission
bash -x script.sh Run with debug output
set -e Exit on first error
set -u Exit on undefined variable
set -o pipefail Exit on pipe failure
set -euo pipefail Strict mode (recommended)

Variables

Pattern Description
NAME="value" Assign variable (no spaces around =)
echo "$NAME" Use variable (always quote!)
echo "${NAME}" Use with braces (safer)
readonly PI=3.14 Constant (cannot be changed)
unset NAME Delete variable
export NAME="value" Export to child processes
local name="value" Local variable (inside functions)
NAME="${1:-default}" Default value if $1 is unset
NAME="${VAR:?error msg}" Error if VAR is unset
NAME="${VAR:+alt}" Use alt if VAR is set

Special Variables

Variable Description
$0 Script name
$1, $2... Positional arguments
$# Number of arguments
$@ All arguments (as separate words)
$* All arguments (as single string)
$? Exit code of last command
$$ Current script PID
$! PID of last background process
$_ Last argument of previous command

String Operations

Pattern Description
${#str} String length
${str:0:5} Substring (first 5 chars)
${str:3} Substring (from index 3)
${str^^} Uppercase
${str,,} Lowercase
${str^} Capitalize first letter
${str/old/new} Replace first occurrence
${str//old/new} Replace all occurrences
${str#pattern} Remove shortest prefix match
${str##pattern} Remove longest prefix match
${str%pattern} Remove shortest suffix match
${str%%pattern} Remove longest suffix match

Arithmetic

Pattern Description
$((a + b)) Addition
$((a - b)) Subtraction
$((a * b)) Multiplication
$((a / b)) Division (integer)
$((a % b)) Modulo
$((a ** b)) Exponentiation
((a++)) Increment
((a--)) Decrement
((a += 5)) Add and assign

Conditionals

Pattern Description
if [[ condition ]]; then ... fi If statement
if [[ cond ]]; then ... else ... fi If-else
if [[ cond ]]; then ... elif [[ cond ]]; then ... fi If-elif-else
[[ cond ]] && cmd Short-circuit AND
[[ cond ]] || cmd Short-circuit OR
case "$var" in pattern) ... ;; esac Case/switch

Test Operators

File Tests

Operator Description
-f file File exists and is regular file
-d dir Directory exists
-e path Path exists (any type)
-r file File is readable
-w file File is writable
-x file File is executable
-s file File exists and is not empty
-L file File is a symbolic link
-z "$str" String is empty
-n "$str" String is not empty

String Comparisons

Operator Description
"$a" == "$b" Strings are equal
"$a" != "$b" Strings are not equal
"$a" < "$b" String less than (alphabetical)
"$a" =~ regex Regex match (in [[ ]])

Numeric Comparisons

Operator Description
$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

Logical Operators

Operator Description
&& AND
|| OR
! NOT

Loops

Pattern Description
for i in 1 2 3; do ... done For-in loop
for i in {1..10}; do ... done Range loop
for ((i=0; i<10; i++)); do ... done C-style for loop
for f in *.txt; do ... done Loop over files
while [[ cond ]]; do ... done While loop
until [[ cond ]]; do ... done Until loop
while read -r line; do ... done < file Read file line by line
break Exit loop
continue Skip to next iteration

Functions

Pattern Description
func_name() { ... } Define function
func_name arg1 arg2 Call function with arguments
local var="value" Local variable inside function
return 0 Return exit code (0 = success)
result=$(func_name) Capture function output

Arrays

Pattern Description
arr=(a b c) Define array
${arr[0]} Access element
${arr[@]} All elements
${#arr[@]} Array length
arr+=(d) Append element
unset arr[1] Remove element
${arr[@]:1:2} Slice (2 elements from index 1)

Input & Arguments

Pattern Description
read -r var Read user input
read -p "Prompt: " var Read with prompt
read -s var Read silently (passwords)
read -t 5 var Read with 5-second timeout
getopts "ab:c" opt Parse short options
shift Shift arguments left
shift 2 Shift arguments left by 2

Redirection & Pipes

Pattern Description
cmd > file Redirect stdout (overwrite)
cmd >> file Redirect stdout (append)
cmd 2> file Redirect stderr
cmd &> file Redirect both stdout and stderr
cmd 2>&1 Merge stderr into stdout
cmd < file Redirect stdin from file
cmd1 | cmd2 Pipe stdout to next command
cmd | tee file Pipe and save to file
cmd <<< "string" Here-string as stdin

Exit Codes & Error Handling

Pattern Description
exit 0 Exit successfully
exit 1 Exit with error
$? Last exit code
set -e Exit on any error
set -o pipefail Pipe returns last non-zero
trap 'cleanup' EXIT Run cleanup on exit
trap 'handler' ERR Run handler on error
cmd || true Ignore error from cmd
cmd || { echo "failed"; exit 1; } Custom error handling

String Manipulation

Pattern Result
file="report.tar.gz"
${file%.tar.gz} report (remove suffix)
${file##*.} gz (get extension)
${file%.*} report.tar (remove last ext)
path="/home/user/file.txt"
$(basename "$path") file.txt
$(dirname "$path") /home/user
${path##*/} file.txt (basename without cmd)

File Operations

Pattern Description
[[ -f "$file" ]] && cat "$file" Read file if exists
while IFS= read -r line; do echo "$line"; done < file Read line by line
mapfile -t lines < file Read file into array
mktemp Create temp file
mktemp -d Create temp directory
trap 'rm -f $tmpfile' EXIT Auto-cleanup temp files

Process Control

Pattern Description
cmd & Run in background
wait Wait for all background jobs
wait $pid Wait for specific PID
exec cmd Replace shell with cmd
exec > logfile 2>&1 Redirect all output to log
$$ Current PID
$! Last background PID
kill $pid Send SIGTERM
kill -9 $pid Send SIGKILL

Docker Entrypoint Patterns

Pattern Description
exec "$@" Pass CMD to entrypoint (standard)
exec gosu user "$@" Run CMD as non-root user
envsubst < template > config Template config from env vars
dockerize -wait tcp://db:5432 Wait for dependency
until pg_isready; do sleep 1; done Wait for PostgreSQL

Minimal Entrypoint Template

#!/bin/bash
set -euo pipefail

# Setup / initialization
echo "Starting..."

# Execute CMD
exec "$@"

Useful One-Liners

One-Liner Description
for f in *.jpg; do mv "$f" "${f%.jpg}.png"; done Rename extensions
while true; do cmd; sleep 5; done Repeat every 5 seconds
find . -name "*.log" -exec rm {} + Delete all .log files
cat file | sort | uniq -c | sort -rn Count & sort lines
diff <(cmd1) <(cmd2) Compare command outputs
cmd | while read -r line; do echo "$line"; done Process output line by line