Skip to main content
3 of 7
Was looking for confirmation whether ${var##*.} can be used in /bin/sh, confirmed that.

If the file name is file-1.0.tar.bz2, the extension is bz2. The method you're using to extract the extension (fileext=${filename##*.}) is perfectly valid, and should work even for non-bash shells as it is mandated by POSIX (see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02).

How do you decide that you want the extension to be tar.bz2 and not bz2 or 0.tar.bz2? You need to answer this question first. Then you can figure out what shell command matches your specification.

  • One possible specification is that extensions must begin with a letter. Here's a bash/ksh/zsh implementation:

     basename=$filename fileext= while [[ $basename = ?*.* && ${basename##*.} = [A-Za-z]* ]]; do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.} 

ADDED: one common extension for which this heuristic fails is 7z.

  • Another possible specification is that some extensions denote encodings and indicate that further stripping is needed. Here's a bash/ksh/zsh implementation (requiring shopt -s extglob under bash and setopt ksh_glob under zsh):

     basename=$filename fileext= while [[ $basename = ?*.@(bz2|gz|lzma) ]]; do fileext=${basename##*.}.$fileext basename=${basename%.*} done if [[ $basename = ?*.* ]]; then fileext=${basename##*.}.$fileext basename=${basename%.*} fi fileext=${fileext%.} 

Note that this considers 0 to be an extension in file-1.0.gz.

Gilles 'SO- stop being evil'
  • 865.9k
  • 205
  • 1.8k
  • 2.3k