Shell Scripting Cheatsheet
Table of Contents
- Script Basics
- Variables
- String Operations
- Arithmetic
- Conditionals
- Test Operators
- Loops
- Functions
- Arrays
- Input & Arguments
- Redirection & Pipes
- Exit Codes & Error Handling
- String Manipulation
- File Operations
- Process Control
- Docker Entrypoint Patterns
- 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) |
| 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 |