Simply said, pattern substitution allows us to substitute a pattern with something else (who would have thought!). This is what we could already do with sed:
reader@ubuntu:~/scripts/chapter_16$ echo "Hi"
Hi
reader@ubuntu:~/scripts/chapter_16$ echo "Hi" | sed 's/Hi/Bye/'
Bye
Initially, our echo contains the word Hi. We then pipe it through sed, in which we look for the pattern Hi, which we will substitute with Bye. The s at the front of the instruction to sed signals that we're searching and replacing.
Behold, after sed is done parsing the stream, we end up with Bye on our screen.
If we want to do the same when using a variable, we have two options: we'll either parse it through sed as we did previously, or we'll turn to our new best friend for another great parameter expansion:
Pattern substitution. The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string.
So, for the ${sentence} variable, we could replace the first instance of a pattern with ${sentence/pattern/string}, or all instances of the pattern with ${sentence//pattern/string} (notice the extra forward slash).
On the command line, it might look something like this:
reader@ubuntu:~$ sentence="How much wood would a woodchuck chuck if a woodchuck could chuck wood?"
reader@ubuntu:~$ echo ${sentence}
How much wood would a woodchuck chuck if a woodchuck could chuck wood?
reader@ubuntu:~$ echo ${sentence/wood/stone}
How much stone would a woodchuck chuck if a woodchuck could chuck wood?
reader@ubuntu:~$ echo ${sentence//wood/stone}
How much stone would a stonechuck chuck if a stonechuck could chuck stone
reader@ubuntu:~$ echo ${sentence}
How much wood would a woodchuck chuck if a woodchuck could chuck wood?
Once again, this is pretty self-explanatory and simple to use.
One important thing to realize is that this parameter expansion doesn't actually edit the value of the variable: it only affects the current substitution. If you wanted to do a permanent manipulation of the variable, you'd need to write the result to a variable again, as follows:
reader@ubuntu:~$ sentence_mutated=${sentence//wood/stone}
reader@ubuntu:~$ echo ${sentence_mutated}
How much stone would a stonechuck chuck if a stonechuck could chuck stone?
Or, if you'd prefer to keep the variable name after the mutation, you can assign the mutated value back to the variable in one go, as follows:
reader@ubuntu:~$ sentence=${sentence//wood/stone}
reader@ubuntu:~$ echo ${sentence}
How much stone would a stonechuck chuck if a stonechuck could chuck stone?
It should not be too difficult to imagine using this syntax in a script. As a simple example, we've created a little interactive quiz in which we'll help the user if they happen to give the wrong answer to our very non-opinionated question:
reader@ubuntu:~/scripts/chapter_16$ vim forbidden-word.sh
#!/bin/bash
#####################################
# Author: Sebastiaan Tammer
# Version: v1.0.0
# Date: 2018-12-16
# Description: Blocks the use of the forbidden word!
# Usage: ./forbidden-word.sh
#####################################
read -p "What is your favorite shell? " answer
echo "Great choice, my favorite shell is also ${answer/zsh/bash}!"
reader@ubuntu:~/scripts/chapter_16$ bash forbidden-word.sh
What is your favorite shell? bash
Great choice, my favorite shell is also bash!
reader@ubuntu:~/scripts/chapter_16$ bash forbidden-word.sh
What is your favorite shell? zsh
Great choice, my favorite shell is also bash!
In this script, if the user is temporarily confused and does not give the wanted answer, we'll simply replace their wrong answer (zsh) with the correct answer, bash.
All jokes aside, other shells such as zsh, ksh, and even the newer fish have their own unique selling points and strengths that makes some users prefer them over Bash for daily work. This is obviously great, and a big part of the mentality of using Linux: you have the freedom to choose whichever software you prefer!
When it comes to scripting, however, we are (obviously) of the opinion that Bash is still the king of shells, if only for the very simple reason that it has become the de facto shell for most distributions. This is very helpful when it comes to portability and interoperability, qualities that are often beneficial for scripts.