Linux and Bash course menu
Bash Arrays and String Manipulation
Use indexed and associative arrays in Bash, loop over them safely, and handle strings with parameter expansion: length, substrings, replacing text and trimming file extensions.
On this page
Arrays#
An array holds a list of values. Brackets create one, with spaces between items:
fruits=("apple" "green mango" "kiwi")
echo "${fruits[0]}"
echo "${fruits[1]}"
echo "Count: ${#fruits[@]}"apple
green mango
Count: 3Numbering starts at 0. Add to an array with +=:
fruits=("apple" "kiwi")
fruits+=("guava")
echo "${fruits[@]}"
echo "${fruits[@]:1:2}"apple kiwi guava
kiwi guava${fruits[@]:1:2} takes two items, starting at index 1.
Loop over an array#
Quote it as "${array[@]}", so that items with spaces stay together:
servers=("web 1" "web 2")
for s in "${servers[@]}"; do
echo "Checking $s"
doneChecking web 1
Checking web 2Fill an array from a command#
mapfile reads lines into an array, safely:
printf 'one\ntwo\nthree\n' > items.txt
mapfile -t items < items.txt
echo "${#items[@]} items, last is ${items[-1]}"3 items, last is threeAssociative arrays#
These use text keys, like a dictionary. They must be declared with declare -A:
declare -A port
port[web]=80
port[ssh]=22
echo "ssh uses ${port[ssh]}"
for name in "${!port[@]}"; do
echo "$name ${port[$name]}"
done | sortssh uses 22
ssh 22
web 80"${!port[@]}" gives the keys. They come in no fixed order, so we sort them.
This is useful for counting:
declare -A seen
for word in red blue red red; do
((seen[$word]++))
done
echo "red=${seen[red]} blue=${seen[blue]}"red=3 blue=1String length and substrings#
text="Laviyx Learn"
echo "${#text}"
echo "${text:0:6}"
echo "${text: -5}"12
Laviyx
Learn${text:start:length} takes part of a string. The space before -5 is needed.
Replace text#
path="a-b-c"
echo "${path/-/_}"
echo "${path//-/_}"a_b-c
a_b_cOne / replaces the first match, and two replace them all.
Trim from either end#
# removes from the start, and % from the end. Doubling them removes as much as possible:
These are the standard way to handle paths:
file="/var/log/app.tar.gz"
echo "${file##*/}"
echo "${file%/*}"
echo "${file%.gz}"
name="${file##*/}"
echo "${name%%.*}"
echo "${name#*.}"app.tar.gz
/var/log
/var/log/app.tar
app
tar.gzThe first two give the same results as basename and dirname, without starting a new program.
Upper and lower case#
word="Hello"
echo "${word^^}"
echo "${word,,}"HELLO
helloSplit a string#
Use IFS with read:
line="asha:admin:hyderabad"
IFS=: read -r user role city <<< "$line"
echo "$user lives in $city"
IFS=, read -ra parts <<< "a,b,c"
echo "${#parts[@]} parts"asha lives in hyderabad
3 parts<<< is a here string, which feeds one string to a command.
Common mistakes#
Practice#
Practice exercise
Given files=("photo.JPG" "notes.txt" "song.mp3"), print each file's extension in lower case.
Show solution
files=("photo.JPG" "notes.txt" "song.mp3")
for f in "${files[@]}"; do
ext="${f##*.}"
echo "${ext,,}"
donejpg
txt
mp3Key takeaway#
Next: Writing Safe Scripts.
Finished this lesson?