Bash String Manipulation & Variable
Initialization
Part 1: Variable Initialization
Basic Variable Assignment
bash
# Simple assignment (no spaces around =)
name="John"
age=25
empty=""
# Using command output
current_date=$(date)
files=$(ls)
# Using backticks (old style, avoid)
user=`whoami`
Variable Types
bash
# String
str="Hello World"
# Integer
num=42
# Array
arr=("apple" "banana" "cherry")
# Associative array (Bash 4+)
declare -A dict
dict[key1]="value1"
dict[key2]="value2"
Reading User Input
bash
# Basic read
read username
echo "Hello $username"
# With prompt
read -p "Enter your name: " name
# Silent input (passwords)
read -sp "Enter password: " password
# With timeout
read -t 5 -p "Quick! Enter something: " input
# Read into array
read -a words <<< "one two three"
echo ${words[1]} # Output: two
Default Values & Parameter Expansion
bash
# Use default if unset
echo ${var:-"default"} # If var is unset/empty, use "default"
# Assign default if unset
echo ${var:="default"} # Assigns "default" to var if unset
# Use alternate value if set
echo ${var:+"alternate"} # If var is set, use "alternate"
# Error if unset
echo ${var:?"Error: var not set"} # Exit with error if unset
Special Variables
bash
$0 # Script name
$1-$9 # Positional parameters (arguments)
$# # Number of arguments
$@ # All arguments as separate words
$* # All arguments as single word
$? # Exit status of last command
$$ # Process ID of current shell
$! # Process ID of last background command
Part 2: String Manipulation
String Length
bash
str="Hello World"
echo ${#str} # Output: 11
# Array length
arr=("a" "b" "c")
echo ${#arr[@]} # Output: 3
Substring Extraction
bash
str="Hello World"
# ${var:offset:length}
echo ${str:0:5} # Output: Hello
echo ${str:6} # Output: World (from position 6 to end)
echo ${str:6:5} # Output: World
echo ${str: -5} # Output: World (last 5 chars, note space before -)
echo ${str: -5:3} # Output: Wor
String Removal (Patterns)
bash
filename="[Link]"
# Remove from beginning (shortest match)
echo ${filename#*.} # Output: [Link]
# Remove from beginning (longest match)
echo ${filename##*.} # Output: gz
# Remove from end (shortest match)
echo ${filename%.*} # Output: [Link]
# Remove from end (longest match)
echo ${filename%%.*} # Output: document
Mnemonic: # removes from front, % removes from back
Search and Replace
bash
str="I love apples and apples are great"
# Replace first occurrence
echo ${str/apples/oranges}
# Output: I love oranges and apples are great
# Replace all occurrences
echo ${str//apples/oranges}
# Output: I love oranges and oranges are great
# Replace at beginning
echo ${str/#I/You}
# Output: You love apples and apples are great
# Replace at end
echo ${str/%great/awesome}
# Output: I love apples and apples are awesome
# Delete pattern
echo ${str//apples/}
# Output: I love and are great
Case Conversion (Bash 4+)
bash
str="Hello World"
# To uppercase
echo ${str^^} # Output: HELLO WORLD
echo ${str^^[aeiou]} # Output: HEllO WOrld (specific chars)
# To lowercase
echo ${str,,} # Output: hello world
echo ${str,,[HW]} # Output: hello world (specific chars)
# Toggle first character
echo ${str^} # Output: Hello World
echo ${str,} # Output: hello World
String Concatenation
bash
# Simple concatenation
first="Hello"
last="World"
full="$first $last" # Hello World
full="${first}${last}" # HelloWorld
# Append to variable
str="Hello"
str+=" World" # Hello World
str+="!" # Hello World!
String Comparison
bash
str1="hello"
str2="world"
# Equality
if [ "$str1" = "$str2" ]; then
echo "Equal"
fi
# Inequality
if [ "$str1" != "$str2" ]; then
echo "Not equal"
fi
# Less than (alphabetically)
if [[ "$str1" < "$str2" ]]; then
echo "str1 comes before str2"
fi
# Check if empty
if [ -z "$str1" ]; then
echo "String is empty"
fi
# Check if not empty
if [ -n "$str1" ]; then
echo "String is not empty"
fi
Pattern Matching
bash
str="hello123world"
# Check if matches pattern
if [[ $str == *"123"* ]]; then
echo "Contains 123"
fi
# Regex matching (Bash 3+)
if [[ $str =~ [0-9]+ ]]; then
echo "Contains numbers"
echo "Matched: ${BASH_REMATCH[0]}"
fi
# Case-insensitive matching (Bash 4+)
shopt -s nocasematch
if [[ "HELLO" == "hello" ]]; then
echo "Match (case-insensitive)"
fi
shopt -u nocasematch
Part 3: Advanced Techniques
Here Documents
bash
# Multi-line string
cat << EOF
This is a
multi-line
string
EOF
# With variable expansion
name="John"
cat << EOF
Hello $name
Welcome!
EOF
# Without variable expansion (quoted delimiter)
cat << 'EOF'
$name will not expand
EOF
# Assign to variable
content=$(cat << EOF
Line 1
Line 2
EOF
)
Arrays
bash
# Indexed arrays
fruits=("apple" "banana" "cherry")
# Access elements
echo ${fruits[0]} # apple
echo ${fruits[@]} # all elements
echo ${fruits[*]} # all elements (different in quotes)
# Array length
echo ${#fruits[@]} #3
# Slice array
echo ${fruits[@]:1:2} # banana cherry
# Add elements
fruits+=("date")
fruits[10]="elderberry"
# Loop through array
for fruit in "${fruits[@]}"; do
echo $fruit
done
# Get indices
echo ${!fruits[@]} # 0 1 2 3 10
Associative Arrays (Bash 4+)
bash
# Declare
declare -A person
# Assign
person[name]="John"
person[age]=30
person[city]="NYC"
# Access
echo ${person[name]}
# All keys
echo ${!person[@]}
# All values
echo ${person[@]}
# Loop
for key in "${!person[@]}"; do
echo "$key: ${person[$key]}"
done
String Splitting
bash
# Split by IFS (Internal Field Separator)
IFS=',' read -ra parts <<< "a,b,c,d"
echo ${parts[1]} #b
# Split into array
str="one:two:three"
IFS=':' read -ra arr <<< "$str"
# Using parameter expansion
str="apple-banana-cherry"
IFS='-' read -ra fruits <<< "$str"
Exercises
Exercise 1: Basic Variables
Write a script that:
1. Prompts for first name and last name
2. Creates a full name variable
3. Converts to uppercase
4. Prints the length of the full name
Expected output:
Enter first name: john
Enter last name: doe
Full name: JOHN DOE
Length: 8
Exercise 2: File Extension Handler
Write a script that:
1. Takes a filename as argument
2. Extracts the filename without extension
3. Extracts just the extension
4. Prints both
Example:
bash
./[Link] [Link]
Filename: document
Extension: gz
Full extension: [Link]
Exercise 3: URL Parser
Parse a URL and extract components:
bash
url="[Link]
Extract:
• Protocol (https)
• Domain ([Link])
• Port (8080)
• Path (/path/to/page)
• Query (query=value)
• Fragment (section)
Exercise 4: String Replacement
Write a script that:
1. Takes a sentence as input
2. Replaces all vowels with asterisks
3. Counts how many replacements were made
Exercise 5: Password Validator
Create a password validator that checks:
• Minimum 8 characters
• Contains at least one uppercase letter
• Contains at least one lowercase letter
• Contains at least one digit
• Contains at least one special character
Exercise 6: CSV Parser
Parse this CSV line and create an associative array:
John Doe,30,Engineer,New York
Fields: name, age, job, city
Exercise 7: Path Manipulation
Write a script that:
1. Takes a full path: /home/user/documents/[Link]
2. Extracts directory: /home/user/documents
3. Extracts filename: [Link]
4. Extracts basename: file
5. Extracts extension: txt
Exercise 8: Email Validator
Write a function that validates if a string is a valid email:
• Contains exactly one @
• Has characters before @
• Has a domain after @
• Domain has at least one dot
Exercise 9: Word Counter
Count occurrences of each word in a sentence (case-insensitive).
Input: "The quick brown fox jumps over the lazy dog" Output:
the: 2
quick: 1
brown: 1
...
Exercise 10: Template Engine
Create a simple template replacer:
bash
template="Hello {name}, you are {age} years old"
Replace {name} and {age} with actual values from an associative array.
Solutions (Try yourself first!)
Solution 1: Basic Variables
bash
#!/bin/bash
read -p "Enter first name: " first
read -p "Enter last name: " last
full="$first $last"
upper="${full^^}"
echo "Full name: $upper"
echo "Length: ${#full}"
Solution 2: File Extension Handler
bash
#!/bin/bash
filename="$1"
basename="${filename%%.*}"
extension="${filename##*.}"
full_ext="${filename#*.}"
echo "Filename: $basename"
echo "Extension: $extension"
echo "Full extension: $full_ext"
Solution 3: URL Parser
bash
#!/bin/bash
url="[Link]
# Protocol
protocol="${url%%://*}"
echo "Protocol: $protocol"
# Remove protocol
rest="${url#*://}"
# Domain and port
domain_port="${rest%%/*}"
domain="${domain_port%%:*}"
port="${domain_port#*:}"
echo "Domain: $domain"
echo "Port: $port"
# Path
path="${rest#*/}"
path="${path%%\?*}"
path="${path%%#*}"
echo "Path: /$path"
# Query
if [[ $url == *"?"* ]]; then
query="${url#*\?}"
query="${query%%#*}"
echo "Query: $query"
fi
# Fragment
if [[ $url == *"#"* ]]; then
fragment="${url##*#}"
echo "Fragment: $fragment"
fi
Solution 4: String Replacement
bash
#!/bin/bash
read -p "Enter sentence: " sentence
original_len=${#sentence}
replaced="${sentence//[aeiouAEIOU]/*}"
replaced_len=${#replaced}
count=$((original_len - replaced_len + ${#replaced//[^*]/}))
echo "Result: $replaced"
echo "Replacements: $count"
Solution 5: Password Validator
bash
#!/bin/bash
validate_password() {
local pass="$1"
[[ ${#pass} -ge 8 ]] || { echo "Too short"; return 1; }
[[ $pass =~ [A-Z] ]] || { echo "Need uppercase"; return 1; }
[[ $pass =~ [a-z] ]] || { echo "Need lowercase"; return 1; }
[[ $pass =~ [0-9] ]] || { echo "Need digit"; return 1; }
[[ $pass =~ [^a-zA-Z0-9] ]] || { echo "Need special char"; return 1; }
echo "Valid password!"
return 0
}
read -sp "Enter password: " password
echo
validate_password "$password"
Quick Reference Card
bash
# Length
${#var}
# Substring
${var:offset:length}
# Remove shortest from start
${var#pattern}
# Remove longest from start
${var##pattern}
# Remove shortest from end
${var%pattern}
# Remove longest from end
${var%%pattern}
# Replace first
${var/pattern/replacement}
# Replace all
${var//pattern/replacement}
# Uppercase
${var^^}
# Lowercase
${var,,}
# Default value
${var:-default}
# Assign default
${var:=default}