Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

Consider the following bash script:

#!/bin/bash
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)

share|improve this question

marked as duplicate by jasonwryan, polym, goldilocks, Ramesh, Gilles Jul 31 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.

3 Answers 3

up vote 23 down vote accepted

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.

share|improve this answer
4  
Wonderful answer. Clear as a bell, and I have learned something new which should be helpful in my bash scripts. –  Warwick Jul 31 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 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 at 17:44

Simple example:

$ A=my.file.name.txt

$ echo ${A}
my.file.name.txt

$ echo ${A#m}
y.file.name.txt

$ echo ${A#my}
.file.name.txt

$ echo ${A#*.}
file.name.txt

$ echo ${A##*.}
txt

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

share|improve this answer

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

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