That's documented in the bash manual under Shell Parameter Expansion:
${parameter%word}
${parameter%%word}
The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is the value of parameter with the shortest matching pattern (the %
case) or the longest matching pattern (the %%
case) deleted. If parameter is @
or *
, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @
or *
, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.
In other words, ${f%????}
is the value of $f
with the four last characters deleted.
You could also write ${f:0:-4}
, which is perhaps a bit clearer.