📖 Guide
Bash — Complete Reference
Comprehensive Bash cheat sheet covering variables, strings, arrays, conditionals, loops, functions, file tests, I/O redirection, process management, and more.
166 commands across 11 categories
VariablesString OperationsArraysConditionalsLoopsFunctionsFile TestsI/O RedirectionProcess ManagementText ProcessingScript Best Practices
Variables
| Command | Description |
|---|---|
NAME="value" | Assign a variable (no spaces around =) |
echo "$NAME" | Access variable value (double quotes preserve spaces) |
echo "${NAME}" | Access variable with braces (for clarity/concatenation) |
readonly PI=3.14 | Declare a read-only (constant) variable |
unset NAME | Remove a variable |
export NAME="value" | Export variable to child processes |
local var="value" | Declare local variable inside a function |
${NAME:-default}e.g. echo "${USER:-anonymous}" | Use default if variable is unset or empty |
${NAME:=default} | Assign default if variable is unset or empty |
${NAME:+alt}e.g. echo "${DEBUG:+--verbose}" | Use alt value if variable IS set |
${NAME:?error msg} | Exit with error if variable is unset |
$0, $1, $2 ... | Script name ($0) and positional arguments |
$# | Number of arguments passed to script |
$@ | All arguments as separate words |
$* | All arguments as a single string |
$? | Exit status of last command (0 = success) |
$$ | PID of the current shell |
$! | PID of last background process |
String Operations
| Command | Description |
|---|---|
${#string}e.g. name="hello"; echo ${#name} # 5 | Length of string |
${string:offset:length}e.g. echo ${name:1:3} # ell | Substring extraction |
${string#pattern}e.g. f="file.tar.gz"; echo ${f#*.} # tar.gz | Remove shortest match from beginning |
${string##pattern}e.g. echo ${f##*.} # gz | Remove longest match from beginning |
${string%pattern}e.g. echo ${f%.*} # file.tar | Remove shortest match from end |
${string%%pattern}e.g. echo ${f%%.*} # file | Remove longest match from end |
${string/old/new} | Replace first occurrence |
${string//old/new} | Replace all occurrences |
${string^} | Uppercase first character |
${string^^} | Uppercase all characters |
${string,} | Lowercase first character |
${string,,} | Lowercase all characters |
Arrays
| Command | Description |
|---|---|
arr=(one two three) | Declare an indexed array |
arr[0]="value" | Assign value to specific index |
echo "${arr[0]}" | Access element by index |
echo "${arr[@]}" | All elements |
echo "${#arr[@]}" | Number of elements |
arr+=("new") | Append element to array |
unset arr[1] | Remove element at index |
echo "${arr[@]:1:2}" | Slice: 2 elements starting from index 1 |
echo "${!arr[@]}" | All indices of the array |
for item in "${arr[@]}"; do echo "$item"; done | Iterate over array elements |
declare -A map | Declare an associative array (dictionary) |
map[key]="value" | Set value in associative array |
echo "${!map[@]}" | All keys of associative array |
Conditionals
| Command | Description |
|---|---|
if [[ condition ]]; then ... elif ...; then ... else ... fi | If-elif-else block |
[[ -z "$str" ]] | True if string is empty |
[[ -n "$str" ]] | True if string is not empty |
[[ "$a" == "$b" ]] | String equality |
[[ "$a" != "$b" ]] | String inequality |
[[ "$a" =~ regex ]]e.g. [[ "$email" =~ ^[a-z]+@[a-z]+\.[a-z]+$ ]] | Regex match |
[[ "$a" < "$b" ]] | String less than (lexicographic) |
[[ $a -eq $b ]] | Numeric equality |
[[ $a -ne $b ]] | Numeric inequality |
[[ $a -lt $b ]] | Numeric less than |
[[ $a -le $b ]] | Numeric less than or equal |
[[ $a -gt $b ]] | Numeric greater than |
[[ $a -ge $b ]] | Numeric greater than or equal |
[[ cond1 && cond2 ]] | Logical AND |
[[ cond1 || cond2 ]] | Logical OR |
[[ ! condition ]] | Logical NOT |
case "$var" in pattern) cmd ;; *) default ;; esac | Case statement (pattern matching) |
Loops
| Command | Description |
|---|---|
for i in 1 2 3; do echo $i; done | For loop over list |
for i in {1..10}; do echo $i; done | For loop with brace expansion |
for i in {0..100..5}; do echo $i; done | Brace expansion with step |
for ((i=0; i<10; i++)); do echo $i; done | C-style for loop |
for f in *.txt; do echo "$f"; done | Loop over files matching glob |
while [[ condition ]]; do ...; done | While loop |
while read -r line; do echo "$line"; done < file.txt | Read file line by line |
until [[ condition ]]; do ...; done | Until loop (runs while condition is false) |
break | Exit the current loop |
continue | Skip to next iteration |
while true; do ...; sleep 1; done | Infinite loop |
select opt in "A" "B" "Quit"; do case $opt in ... | Select menu (interactive choice) |
Functions
| Command | Description |
|---|---|
function_name() { commands; } | Define a function |
function name { commands; } | Alternative function syntax |
function_name arg1 arg2 | Call function with arguments |
$1, $2 ... inside function | Access function arguments |
local var="value" | Declare local variable (scoped to function) |
return 0 | Return exit status from function (0-255) |
result=$(function_name)e.g. greet() { echo "Hello"; }; msg=$(greet) | Capture function output |
trap 'cleanup' EXIT | Run cleanup function on script exit |
trap 'echo caught' SIGINT | Handle Ctrl+C signal |
set -e | Exit immediately on error |
set -u | Treat unset variables as errors |
set -o pipefail | Pipe fails if any command fails |
File Tests
| Command | Description |
|---|---|
[[ -e file ]] | True if file exists |
[[ -f file ]] | True if regular file exists |
[[ -d dir ]] | True if directory exists |
[[ -L file ]] | True if symbolic link exists |
[[ -r file ]] | True if file is readable |
[[ -w file ]] | True if file is writable |
[[ -x file ]] | True if file is executable |
[[ -s file ]] | True if file is not empty (size > 0) |
[[ -p file ]] | True if file is a named pipe |
[[ file1 -nt file2 ]] | True if file1 is newer than file2 |
[[ file1 -ot file2 ]] | True if file1 is older than file2 |
I/O Redirection
| Command | Description |
|---|---|
cmd > file | Redirect stdout to file (overwrite) |
cmd >> file | Redirect stdout to file (append) |
cmd 2> file | Redirect stderr to file |
cmd &> file | Redirect both stdout and stderr to file |
cmd 2>&1 | Redirect stderr to stdout |
cmd < file | Read stdin from file |
cmd1 | cmd2 | Pipe stdout of cmd1 to stdin of cmd2 |
cmd1 |& cmd2 | Pipe both stdout and stderr to cmd2 |
cat <<EOF\ntext\nEOF | Here document — multi-line input |
cmd <<< "string" | Here string — pass string as stdin |
exec 3> file | Open file descriptor 3 for writing |
echo "data" >&3 | Write to file descriptor 3 |
exec 3>&- | Close file descriptor 3 |
cmd > /dev/null 2>&1 | Suppress all output |
tee filee.g. cmd | tee output.log | Read stdin, write to stdout AND file |
Process Management
| Command | Description |
|---|---|
cmd & | Run command in background |
jobs | List background jobs |
fg %1 | Bring job 1 to foreground |
bg %1 | Resume stopped job in background |
kill PID | Send SIGTERM to process |
kill -9 PID | Send SIGKILL (force kill) |
kill -0 PID | Check if process is running (exit 0 = alive) |
wait | Wait for all background jobs to finish |
wait $PID | Wait for specific process to finish |
nohup cmd & | Run command immune to hangup signal |
ps aux | List all running processes |
ps aux | grep pattern | Find processes by name |
pgrep -f pattern | Get PIDs matching pattern |
pkill -f pattern | Kill processes matching pattern |
top / htop | Interactive process viewer |
cmd1 && cmd2 | Run cmd2 only if cmd1 succeeds |
cmd1 || cmd2 | Run cmd2 only if cmd1 fails |
(cmd1; cmd2) | Run commands in a subshell |
{ cmd1; cmd2; } | Group commands in current shell |
Text Processing
| Command | Description |
|---|---|
grep "pattern" file | Search for pattern in file |
grep -r "pattern" dir/ | Recursive search in directory |
grep -i "pattern" file | Case-insensitive search |
grep -n "pattern" file | Show line numbers |
grep -c "pattern" file | Count matching lines |
grep -v "pattern" file | Invert match (non-matching lines) |
grep -E "regex" file | Extended regex (egrep) |
sed 's/old/new/g' filee.g. sed -i 's/foo/bar/g' file.txt # in-place edit | Replace all occurrences in file |
sed -n '5,10p' file | Print lines 5-10 |
sed '/pattern/d' file | Delete lines matching pattern |
awk '{print $1}' file | Print first field of each line |
awk -F: '{print $1}' /etc/passwd | Use custom field separator |
awk 'NR==5' file | Print 5th line |
sort file | Sort lines alphabetically |
sort -n file | Sort numerically |
sort -u file | Sort and remove duplicates |
uniqe.g. sort file | uniq -c # count occurrences | Remove adjacent duplicate lines |
cut -d',' -f1,3 file | Extract fields 1 and 3 (comma-delimited) |
wc -l file | Count lines in file |
head -n 20 file | Show first 20 lines |
tail -n 20 file | Show last 20 lines |
tail -f file | Follow file (live updates) |
tr 'a-z' 'A-Z'e.g. echo "hello" | tr 'a-z' 'A-Z' # HELLO | Translate characters |
xargse.g. find . -name "*.log" | xargs rm | Build command from stdin |
Script Best Practices
| Command | Description |
|---|---|
#!/bin/bash | Shebang line — specify interpreter |
#!/usr/bin/env bash | Portable shebang (finds bash in PATH) |
set -euo pipefail | Strict mode: exit on error, unset vars, pipe fails |
"$variable" | Always quote variables to prevent word splitting |
[[ ]] vs [ ] | Prefer [[ ]] (no word splitting, supports regex/&&/||) |
$(command) | Command substitution (preferred over backticks) |
$((expression))e.g. echo $((5 + 3 * 2)) # 11 | Arithmetic expansion |
shellcheck script.sh | Lint bash scripts for common errors |
mktempe.g. tmpfile=$(mktemp); echo "data" > "$tmpfile" | Create a secure temporary file |
getopts "ab:c" opte.g. while getopts "v:o:" opt; do case $opt in v) VER=$OPTARG;; esac; done | Parse command-line options |
date +"%Y-%m-%d %H:%M:%S" | Format current date/time |
dirname "$0" / basename "$0" | Get directory/filename of script |
command -v proge.g. command -v git &>/dev/null || echo "git not found" | Check if a command exists (portable) |
📖 Free, searchable command reference. Bookmark this page for quick access.