This question already has an answer here:

Consider the following bash script:

echo "${1##*.}" 

This script prints the extension of a file if the file name is supplied as the first command line argument, something like following:

$ ./script.sh ./file.pdf

In the above case pdf is printed.

Please explain how the expression ${1##*.} is able to extract the extension of the file.

(I understand what $0, $1, $2, $# do in bash and also understand about regular expressions to some extent)

marked as duplicate by jasonwryan, polym, goldilocks, Ramesh, Gilles bash Jul 31 '14 at 22:44

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.


Bash parameter expansion supports several modifications it can do to the value while expanding a variable. One of them is ##, which removes the longest prefix of the value matching a pattern (patterns are not regular expressions here).

In this case the pattern is *.. That matches any zero or more characters followed by a .. ${x##*.} means to remove all of the string up to the last . character, and leave everything after that dot.

${1##*.} means to do that expansion using the value of the first positional parameter, the one you'd usually access with $1. The final result of

echo "${1##*.}"

is then to print out the part of the first argument of the script that comes after the last ., which is the filename extension.

If the pattern doesn't match at all, the full value of the variable is expanded, just as if you hadn't used the ##. In this case, if the argument you gave didn't have a . in it at all then you'd just get it back out again.

Bash also supports a single # to take the shortest matching prefix off, and the same thing with % to match the end of the string instead.

  • 4
    Wonderful answer. Clear as a bell, and I have learned something new which should be helpful in my bash scripts. – Warwick Jul 31 '14 at 3:10
  • @mikeserv: Fair point on non-matching expansion (edited). This is explicitly a Bash question, though, so I'm not going to go all POSIX on it this time. – Michael Homer Jul 31 '14 at 4:10
  • and fair enough about not going all POSIXy. I just thought something like bash supported parameter expansion as opposed to bash parameter expansion would be nearer the mark. – mikeserv Jul 31 '14 at 17:44

Simple example:

$ A=my.file.name.txt

$ echo ${A}

$ echo ${A#m}

$ echo ${A#my}

$ echo ${A#*.}

$ echo ${A##*.}

In a script, ${1} is the first argument, and the same concept applies.

  • this answer is a perfect complement to the first voted, simple and clear, in 5 lines teaches a lot! – caesarsol Dec 12 '14 at 16:14

Note Bash parameter expansion :

You can trim a string from the head by using # operator

You can trim a string from the tail by using % operator

lets take an example :

[my->prompt]$ VAR="head:string:tail"
[my->prompt]$ echo ${VAR##*:}               //trim from the head -> till the last ':'
[my->prompt]$ echo ${VAR#*:}                //trim from the head -> till the first ':' 
[my->prompt]$ echo ${VAR%%:*}               //trim from the tail <- till the last ':'
[my->prompt]$ echo ${VAR%:*}                //trim from the tail <- till the first ':'
[my->prompt]$ VAR2=${VAR%:*}                //VAR2="head:string"
[my->prompt]$ echo $VAR2
[my->prompt]$ echo ${VAR2#*:}               //trim from the head -> till the first ':' 
  • Hey - whose prompt is that?!? – mikeserv Jul 31 '14 at 17:41
  • Hey!!! its mine but after changing the original prompt message :) – bachN Jul 31 '14 at 18:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.