Arrays store multiple values in a single variable. Declare with arr=(val1 val2 val3) or assign individual elements.
# Declare array colors=("red" "green" "blue") # Access by index (zero-based) echo ${colors[0]} # Output: red echo ${colors[2]} # Output: blue # Assign individual elements colors[3]="yellow" # Get all elements echo ${colors[@]} # Output: red green blue yellow # Get array length echo ${#colors[@]} # Output: 4 # Iterate over array for color in "${colors[@]}"; do echo "$color" done
Use associative arrays (hash maps) with declare -A for key-value pairs:
# Declare associative array declare -A config config[host]="localhost" config[port]="8080" config[user]="admin" # Access by key echo ${config[host]} # Output: localhost # Iterate over keys and values for key in "${!config[@]}"; do echo "$key = ${config[$key]}" done
Pass multi-line text to stdin using <<DELIMITER ... DELIMITER. Useful for embedding SQL, config files, or heredocs.
# Basic here document cat << EOF This is line 1 This is line 2 Variables work: $HOME EOF # Pipe into a command mysql -u root -p << SQL CREATE TABLE users (id INT, name VARCHAR(50)); INSERT INTO users VALUES (1, 'Alice'); SQL # Suppress leading tabs with <<- cat <<- EOF Indented text Tab indentation is stripped EOF
Quote the delimiter to disable variable expansion:
# Variables expanded cat << EOF $HOME is your home directory EOF # Variables not expanded (literal dollar signs) cat << 'EOF' $HOME is shown literally ${VAR} is not expanded EOF
Use [[ $var == pattern ]] for pattern matching in conditionals. Bash supports glob patterns and extended globs.
# Basic pattern matching file="document.pdf" [[ $file == *.pdf ]] && echo "PDF file" # Match any single character with ? filename="file1.txt" [[ $filename == file?.txt ]] && echo "Matches file1.txt, file2.txt, etc." # Match character sets with [...] [[ "test" == [a-z]* ]] && echo "Starts with lowercase" [[ "123" == [0-9]* ]] && echo "Starts with digit"
Enable extended glob patterns with shopt -s extglob for more powerful matching:
shopt -s extglob # ?(pattern) - zero or one occurrence [[ "hello" == ?(hel)lo ]] && echo "Matches" # *(pattern) - zero or more occurrences [[ "aaab" == *(a)b ]] && echo "Matches" # +(pattern) - one or more occurrences [[ "aaab" == +(a)b ]] && echo "Matches" # !(pattern) - anything except pattern [[ "test" == !(abc)* ]] && echo "Does not start with abc"
Bash provides parameter expansion for substring extraction, replacement, and trimming.
filename="document.pdf" # Substring: ${var:offset:length} echo ${filename:0:8} # Output: document # Remove extension: ${var%pattern} echo ${filename%.pdf} # Output: document # Remove prefix: ${var#pattern} path="/home/user/file.txt" echo ${path#/home/} # Output: user/file.txt # Replace first occurrence: ${var/old/new} text="hello hello" echo ${text/hello/hi} # Output: hi hello # Replace all occurrences: ${var//old/new} echo ${text//hello/hi} # Output: hi hi # Default value if unset: ${var:-default} echo ${UNDEFINED:-"no value"} # Output: no value
Combine operations for powerful string processing:
# Extract filename without extension from a path path="/home/user/documents/report.pdf" name=${path##*/} # Get filename only: report.pdf base=${name%.*} # Remove extension: report # Uppercase (bash 4+) str="hello" echo ${str^^} # Output: HELLO # Lowercase echo ${str,,} # Output: hello