Bash String Variable Manipulation
Substring by Index
- Syntax:
${var:start:length} - index starts from 0 (unlike awk’s
substr(), which starts from 1)
chars=0123456789ABCDE
echo ${chars:3} # chars[3] to end
echo ${chars:1:0} # length=0 -> empty string
echo ${chars:3:5} # chars[3:8]
## 3456789ABCDE
##
## 34567
Stripping
#and##: stripping the shortest/longest match from start%and%%: stripping the shortest/longest match from end
path=foo/bar/hello.txt
echo ${path#*/}
echo ${path##*/} # get filename
echo ${path%/*} # get dir
echo ${path%%/*}
## bar/hello.txt
## hello.txt
## foo/bar
## foo
Replacement
${var/pattern/replacement}for replacing the first occurence${var//pattern/replacement}for global replacement
path=foo/fizz/bar/fizz_bar.txt
echo ${path/fizz/buzz}
echo ${path//fizz/buzz}
echo ${path/fizz*bar/buzz} # wildcards are allowed
## foo/buzz/bar/fizz_bar.txt
## foo/buzz/bar/buzz_bar.txt
## foo/buzz.txt
#matches only the start%matches only the end
path=fizz/foo/bar/fizz
echo ${path/#fizz/buzz}
echo ${path/%fizz/buzz}
## buzz/foo/bar/fizz
## fizz/foo/bar/buzz
path=foo/foo_data/txt_files/bar.txt
echo ${path/#foo/bar} # changing base dir only
echo ${path/%txt/log} # changing exts only
## bar/foo_data/txt_files/bar.txt
## foo/foo_data/txt_files/bar.log
Exercises
using bash string subsetting:
#!/bin/bash
max_rot() {
num=$1
l=${#num}
max=$num
for (( i=0; i<l; i++ )); do
num=${num:0:$i}${num:$(($i+1))}${num:$i:1}
(( num > max )) && max=$num
done
echo $max
return 0
}
max_rot 123456
## 246351
Note: integer comparison will result in overflow, therefore string comparison is used.
awk version:
max_rot() {
num=$1
l=${#num}
max=$num
for (( i=1; i<l; i++ )); do
num=$(echo $num | awk -v i=$i -v l=$l '{print substr($0,1,i-1)substr($0,i+1,l-i+1)substr($0,i,1)}')
[[ $num > $max ]] && max=$num
done
echo $max
}
max_rot 123456
## 246351