Bash sup­ports a sur­pris­ing num­ber of string manip­u­la­tion oper­a­tions. Unfor­tu­nately, these tools lack a uni­fied focus. Some are a sub­set of para­me­ter sub­sti­tu­tion, and oth­ers fall under the func­tion­al­ity of the UNIX expr com­mand. This results in incon­sis­tent com­mand syn­tax and over­lap of func­tion­al­ity, not to men­tion con­fu­sion. *

This is a short expla­na­tion of Bash’s sub­sti­tion mech­a­nisms I use most fre­quently. For fur­ther infor­ma­tion visit the Advanced Bash-Scripting Guide. The con­struct ${VARIABLE%pattern} removes the short­est pos­si­ble suf­fix of a vari­able string. This is most com­monly used to remove a file­name exten­sion from a vari­able. As pattern we use .* = a dot (.) plus a pos­si­ble num­ber of characters.

:~$ VARIABLE=/home/lisl/dummy.txt
:~$ echo $VARIABLE /home/lisl/dummy.txt
:~$ echo ${VARIABLE%.*} /home/lisl/dummy

While the con­struct ${VARIABLE%.*} removes the short­est pos­si­ble suf­fix of the vari­able string, the con­struct ${VARIABLE%%.*} (=2 times %!) removes the longest pos­si­ble suffix:

:~$ ONEDOT=/home/lisl/dummy.txt
:~$ TWODOT=/home/lisl/.hidden/dummy.txt
:~$ echo ${ONEDOT%.*} /home/lisl/dummy
:~$ echo ${ONEDOT%%.*} /home/lisl/dummy

Within this exam­ple, we get the same out­put, because the string con­tains only one dot and there­fore the longest and the short­est pos­si­ble suf­fix is actu­ally the same. If the string con­tains more than one dot, you will see the difference:

:~$ echo ${TWODOT%.*}
:~$ echo ${TWODOT%%.*} /home/lisl/

To remove the pre­fix instead of the suf­fix you use # instead of %.

:~$ echo ${TWODOT#*.}
:~$ echo ${TWODOT##*.} txt

Best way to start is just by try­ing out. In-depth doc­u­men­ta­tion here.