37

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
Liam
  • 519
  • 1
  • 4
  • 10

3 Answers3

63

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
rici
  • 234,347
  • 28
  • 237
  • 341
  • 8
    In `bash`, you can also use `if [[ $file = *.gz ]]` in place of regular expression matching. – chepner Aug 16 '13 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 Aug 16 '13 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
jthill
  • 55,082
  • 5
  • 77
  • 137
14

You can try something like this:-

if [[ ${file: -3} == ".gz" ]]
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • 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 Aug 16 '13 at 17:56
  • @rici:-Thanx for the suggestion. Updated my answer as well!! :) – Rahul Tripathi Aug 16 '13 at 17:58
  • 4
    You can also use `${file##*.} = gz`, which will work in any POSIX-compliant shell. – chepner Aug 16 '13 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 Aug 16 '13 at 18:34
  • Word splitting doesn't occur for expanded parameters in a `[[ ... ]]` conditional expression, but you are right about the false positive for files named `gz`. – chepner Aug 16 '13 at 18:50
  • Heh. [ -z "${file##*.gz}" ] – jthill Aug 16 '13 at 18:52
  • Is my answer wrong????? – Rahul Tripathi Aug 16 '13 at 19:00
  • Actually I am asking this as it has worked for me in the past. So wanted to know if I am wrong somewhere?? ;-) – Rahul Tripathi Aug 16 '13 at 19:01
  • @chepner: `[[` is not required by Posix; since you said "will work in any POSIX-compliant shell", I assumed you meant with `[` – rici Aug 16 '13 at 19:11
  • @RahulTripathi: No, it's fine. This is just an exploration of alternatives. Since the wrong answer was accepted, we might as well have our fun here. :) – rici Aug 16 '13 at 19:12
  • @rici: oh, right. No point in restricting yourself to POSIX parameter expansion inside a `[[ ... ]]` expression :) – chepner Aug 16 '13 at 19:18
  • This really is sad when you don't get upvoted for right answers and a wrong one is accepted...;-) – Rahul Tripathi Aug 16 '13 at 19:20
  • It isn't that it's wrong for the question as asked, it's that people who need to ask for this are then very confused when their `#!/bin/sh` scripts fail. – jthill Aug 17 '13 at 02:51
  • 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 Jul 19 '19 at 17:04