Script to unpack archives of various kinds Just looking for some feedback and constructive criticism. This is the second script I ever made. Just recently started learning the basics. Anyway just wanted to post the script and see if maybe I can get some input on where I can maybe do things better.
The script is for extracting the compressed file types you run into the most on Linux. I added the option to extract to a directory of the user's choosing and not just keep it limited to only the working directory.
I feel like I have too many if/then statements and they can somehow be better but I'm not sure. And not sure if I Implemented the exits the right way. Some of you are probably gonna cringe when you see this lol! Anyway if you can help thanks.
#!/bin/bash

error() {
    echo &quot;For help, type: nzip -h&quot;
}

usage() {
    echo &quot;Usage: nzip [FILE]...&quot;
    echo &quot;By default file(s) will be extracted to the working directory.&quot;
    echo
    echo &quot;OPTIONS..&quot;
    echo
    echo &quot;-d, --directory, eg. nzip [file] [-d] [directory]&quot;
    echo
    echo
}

if [ $# -eq 0 ]
then
    error &gt;&amp;2
    exit 1
fi

if [ $# -eq 1 ]
then
    case $1 in
        -h) usage
            exit 0
            ;;
        *.7z) 7z e &quot;$1&quot;
            ;;
        *.tar.bz2) tar xjvf &quot;$1&quot;
            ;;
        *.tar.gz) tar xzvf &quot;$1&quot;
            ;;
        *.rar) unrar e &quot;$1&quot;
            ;;
        *.tar) tar xvf &quot;$1&quot;
            ;;
        *.bz2) bunzip2 &quot;$1&quot;
            ;;
        *.tbz) tar xjvf &quot;$1&quot;
            ;;
        *.gz) gunzip &quot;$1&quot;
            ;;
        *.tgz) tar xzvf &quot;$1&quot;
            ;;
        *.jar) unzip &quot;$1&quot;
            ;;
        *.xz) tar xvf &quot;$1&quot;
            ;;
        *.zip) unzip &quot;$1&quot;
            ;;
        *.Z) uncompress &quot;$1&quot;
            ;;
        *) echo &quot;No extraction option for $1&quot; &gt;&amp;2
            exit 1
    esac
    exit 0
fi

if [ $# -eq 3 ] &amp;&amp; [ &quot;$2&quot; = &quot;-d&quot; ]
then
    case $1 in
        *.7z) 7z e &quot;$1&quot; -o&quot;$3&quot;
            ;;
        *.tar.bz2) tar xjvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.tar.gz) tar xzvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.rar) unrar e &quot;$1&quot; &quot;$3&quot;
            ;;
        *.tar) tar xvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.bz2) bunzip2 &quot;$1&quot; -c &gt; &quot;$3&quot;
            ;;
        *.tbz) tar xjvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.gz) gunzip &quot;$1&quot; -c &gt; &quot;$3&quot;
            ;;
        *.tgz) tar xzvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.jar) unzip &quot;$1&quot; -d &quot;$3&quot;
            ;;
        *.xz) tar xvf &quot;$1&quot; -C &quot;$3&quot;
            ;;
        *.zip) unzip &quot;$1&quot; -d &quot;$3&quot;
            ;;
        *.Z) uncompress &quot;$1&quot; -c &gt; &quot;$3&quot;
            ;;
        *) echo &quot;No extraction option for $1&quot; &gt;&amp;2
            exit 1
    esac
else
    error &gt;&amp;2
    exit 1
fi
```
I'm not sure why we have #!/bin/bash - it looks like plain, portable #!/bin/sh would be fine here.
Things I immediately like include the good error handling, using &amp;2 for error messages and exiting non-zero.
All the tar commands can be combined, as tar is able (with -a) to automatically identify any compression scheme it handles.
As there's no need to continue once the archiver is run, we can replace the shell process using exec.  E.g.
case $1 in
    *.7z) exec 7z e &quot;$1&quot;
        ;;

Don't do that if we extend the program to process multiple input files, though (see below).
If we take the usual convention of flags first, then it makes it easier when we decide we want to handle more options (e.g. -v, so we can default to quiet operation).  And we can combine the two big case constructs by always passing a directory, but defaulting to the current working directory:
destination=.

die() {
    printf '%s\n' &quot;$@&quot; &gt;&amp;2
    exit 1
}

do_extract() {
    case $1 in
        *.tar.*|*.t[bg]z) tar xaf &quot;$1&quot; -C &quot;$destination&quot;
            ;;
        *.jar|*.zip) unzip &quot;$1&quot; -d &quot;$destination&quot;
            ;;
        # ...
    esac
}

while [ $# -ge 1 ]
do
    case &quot;$1&quot; in
        -d)
            [ $# -gt 1 ] || die &quot;Usage: $0 [-d directory] file...&quot;
            destination=$2
            shift 2
            ;;
        -*)
            die &quot;Unrecognised option: $1&quot;
        *)
            do_extract &quot;$1&quot;
            shift
    esac
done

Be careful with echo:

usage() {
    echo &quot;Usage: nzip [FILE]...&quot;
    echo &quot;By default file(s) will be extracted to the working directory.&quot;
    echo
    echo &quot;OPTIONS..&quot;
    echo
    echo &quot;-d, --directory, eg. nzip [file] [-d] [directory]&quot;
    echo
    echo
}


Other (e.g. future) versions of echo may treat that -d as indicating a flag.
I'd be inclined to use a here-file for this:
usage() {
    cat &lt;&lt;'END'
Usage: nzip [FILE] [-d DESTINATION]
By default file(s) will be extracted to the working directory.

OPTIONS:
    -d destination
END
}

Note that I've changed the usage line, because we support only one file, and -d and the destination argument go together (and it's misleading to call it &quot;directory&quot; when it may be a non-directory name if we're unpacking a single file).