38

I have a shell script where I need to do one command if a file is zipped (ends in .gz) and another if it is not. I'm not really sure how to approach this, here's an outline of what I'm looking for:

file=/path/name*

if [ CHECK FOR .gz ]
then echo "this file is zipped"
else echo "this file is not zipped"
fi
2
  • 1
    zip != gzip, that should be "this file is (not) gzipped"
    – jlliagre
    Commented Aug 16, 2013 at 17:37
  • 1
    The proper way would be to use file.
    – devnull
    Commented Aug 16, 2013 at 18:17

3 Answers 3

64

You can do this with a simple regex, using the =~ operator inside a [[...]] test:

if [[ $file =~ \.gz$ ]];

This won't give you the right answer if the extension is .tgz, if you care about that. But it's easy to fix:

if [[ $file =~ \.t?gz$ ]];

The absence of quotes around the regex is necessary and important. You could quote $file but there is no point.

It would probably be better to use the file utility:

$ file --mime-type something.gz
something.gz: application/x-gzip

Something like:

if file --mime-type "$file" | grep -q gzip$; then
  echo "$file is gzipped"
else
  echo "$file is not gzipped"
fi
2
  • 8
    In bash, you can also use if [[ $file = *.gz ]] in place of regular expression matching.
    – chepner
    Commented Aug 16, 2013 at 18:27
  • 1
    @chepner, true enough but I wanted to provide the pattern which matches either .gz or .tgz. Admittedly, yours is a bit shorter. I think the file solution is the better choice, though.
    – rici
    Commented Aug 16, 2013 at 18:32
37

Really, the clearest and often easiest way to match patterns like this in a shell script is with case

case "$f" in
*.gz | *.tgz ) 
        # it's gzipped
        ;;
*)
        # it's not
        ;;
esac
2
  • Yes you are right. This is the cleanest IMHO.
    – Nishant
    Commented Nov 13, 2016 at 18:16
  • I like this one the best, actually. It is cleanest by far. Commented Dec 2, 2019 at 19:08
14

You can try something like this:-

if [[ ${file: -3} == ".gz" ]]
14
  • You should use [[ or quote ${file: -3}; otherwise it will break if $file has a space as it's second last character, or (possibly) contains a glob metacharacter in the last three characters.
    – rici
    Commented Aug 16, 2013 at 17:56
  • @rici:-Thanx for the suggestion. Updated my answer as well!! :) Commented Aug 16, 2013 at 17:58
  • 4
    You can also use ${file##*.} = gz, which will work in any POSIX-compliant shell.
    – chepner
    Commented Aug 16, 2013 at 18:29
  • @chepner: Unless the filename is "gz" in which case you'll get a (probably) false positive. (And you should quote the expansion in case the filename has a space in it.)
    – rici
    Commented Aug 16, 2013 at 18:34
  • 1
    I wanted to point out that the space after the colon is important. ${var:-3} is not the same as ${var: -3}; the first (without a space) will expand as '-3' if var is unset the second (with a space) returns the last 3 characters of var.
    – pbatey
    Commented Jul 19, 2019 at 17:04

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