Bash String Manipulation

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

Rotate for a max

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