The ${filename##*.}
expression is parameter expansion ("parameters" being the technical name for the shell feature that other languages call "variables"). Plain ${varname}
is the value of the parameter named varname
, and if that's all you're doing, you can leave off the curly braces and just put $varname
. But if you leave the curly braces there, you can put other things inside them after the name, to modify the result. The #
and %
are some of the most basic modifiers - they remove a prefix or suffix of the string that matches a wildcard pattern. #
removes from the beginning, and %
from the end; in each case, a single instance of the symbol removes the shortest matching string, while a double symbol matches the longest. So ${filename##*.}
is "the value of filename with everything from the beginning to the last period removed", while ${filename%.*}
is "the value of filename with everything from the last period to the end removed".
The backticks syntax (`...`
) is the original way of doing command substitution in the Bourne shell, and has since been borrowed by languages like Perl and Ruby to incorporate calling out to system commands. But it doesn't deal well with nesting, and its attempt to even allow nesting means that quoting works differently inside them, and it's all very confusing. The newer $(...)
syntax, originally introduced in the Korn shell and then adopted by Bash and zsh and codified by POSIX, lets quoting work the same at all levels of a nested substitution and makes for a nice symmetry with the ${...}
parameter expansion.