Advanced Bash: Arrays, String Manipulation, and Regular Expressions
Level up your scripting with arrays, string tricks, arithmetic, pattern matching and here documents.
Arrays: many values in one variable
A normal variable holds one value. An array holds a list of values.
fruits=(apple banana cherry)
echo "${fruits[0]}"
echo "${fruits[@]}"
echo "${#fruits[@]}"
fruits+=(date)
fruits[1]="blueberry"
- Items are numbered from 0.
${fruits[0]}isapple. ${fruits[@]}means all items.${#fruits[@]}is the number of items, here 3.+=(date)adds an item to the end.fruits[1]="blueberry"replaces the second item.
Loop through an array:
for f in "${fruits[@]}"; do
echo "Fruit: $f"
done
The quotes around "${fruits[@]}" keep items that contain spaces as single items.
Associative arrays
An associative array uses names (keys) instead of numbers. It needs Bash 4 or newer.
declare -A age
age[alex]=30
age[sam]=25
echo "Alex is ${age[alex]}"
for name in "${!age[@]}"; do
echo "$name is ${age[$name]}"
done
${!age[@]} gives all the keys.
String tricks
Bash can handle text without calling other programs.
text="Hello, World"
echo "${#text}"
echo "${text:0:5}"
echo "${text:7}"
echo "${text^^}"
echo "${text,,}"
echo "${text/World/Bash}"
${#text}is the length, 12.${text:0:5}is a slice that starts at position 0 and is 5 characters long:Hello.${text:7}starts at position 7 and goes to the end:World.${text^^}converts to uppercase and${text,,}to lowercase.${text/World/Bash}replaces the firstWorldwithBash.
Trimming and defaults
file="report.final.pdf"
echo "${file%.pdf}"
echo "${file##*.}"
echo "${file#*.}"
echo "${name:-guest}"
%removes a matching piece from the end.${file%.pdf}givesreport.final.#removes a matching piece from the start. A single#removes the shortest match, and##removes the longest.${file##*.}removes everything up to the last dot and leaves the extension,pdf.${file#*.}removes up to the first dot and leavesfinal.pdf.${name:-guest}usesguestwhennameis empty.
Arithmetic
echo $((7 + 3))
echo $((17 % 5))
x=$((x + 1))
$(( )) calculates with whole numbers. The operators are + - * / %, and % gives the remainder, so 17 % 5 is 2. Bash does not handle decimals. For decimals use a tool such as bc or awk.
Regular expressions in tests
Inside [[ ]], the =~ operator tests whether text matches a regular expression.
email="alex@example.com"
if [[ $email =~ ^[a-z]+@[a-z]+\.com$ ]]; then
echo "Looks like an email"
fi
^ and $ mark the start and end, [a-z]+ means one or more lowercase letters, and \. is a literal dot.
Here documents
A here document feeds several lines of text into a command. Everything between the two EOF markers is the text.
cat <<EOF > report.txt
User: $USER
Date: $(date +%F)
EOF
The variables and commands inside are replaced, then the text is written to report.txt. The marker name can be any word, but EOF is the common choice, and the closing marker must be on a line by itself.