This is an excellent resource. I'd like to re-iterate the author's recommendation to use shellcheck:

https://www.shellcheck.net/

I also like using shfmt on top of that.

(I run them via pre-commit[1] hooks[2,3].)

FWIW, I find writing POSIX-compliant shell rarely necessary. In my 25 years of writing shell scripts, they've nearly always been for automation on a specific OS where portability is not a concern. Arrays are really nice to have. One place I like to use them is for making long commands easier to read. e.g.

    cmd=(
        some-command
        --some-long-option
        --another-long-option
        --an-option-with-a-value="$value"
    )
    "${cmd[@]}"
This avoids having to use backslashes so you can comment in-between lines or at the end of any line.

I also almost always prefer the self-documenting long-option to single-letter switches when writing shell scripts. Those single-letter options are to save you typing on the command-line. There's no reason to use them in a script.

When I do write a script for more than one OS (typically macOS and Linux), I have bash on both systems, so I use "#!/usr/bin/env bash" and take care to use only the features that the older version of bash that macOS ships with supports.

Where I have to be more careful is in utilities like find, sed, etc which can differ quite a bit between BSD and Linux.

1. https://pre-commit.com/

2. https://github.com/shellcheck-py/shellcheck-py

3. https://github.com/maxwinterstein/shfmt-py

> In my 25 years of writing shell scripts, they've nearly always been for automation on a specific OS where portability is not a concern.

I've written hundreds of scripts for Busybox for Windows (https://github.com/rmyorston/busybox-w32), Linux bash and macOS zsh. POSIX compatibility means a lot.

WRT the specific concerns of arguments: if you are doing something complicated, use Python. ChatGPT writes it better anyway.

In my experience, more complex scripting is reinventing Gradle, Ansible, Terraform, YAML & similar.