Earlier quoted context omitted.
You should be using ShellCheck or an equivalent linter on your shell scripts in POSIX mode if you want them to be portable; in POSIX mode it warns when using "which" instead of "command -v", and I think it also warns when using "whence" or "where" outside of zsh. There's a host of other Bashisms/GNUisms and other noncompliant antipatterns it checks for too. It's also worth reading through the POSIX manpages for POSIX…
> It's also worth reading through the POSIX manpages for POSIX sh if you want to be a good shell scripter. Or you can give the middle finger to POSIX, write shell scripts for bash, or even zsh, and end up with faster, more correct, and more beautiful shell scripts that in practice are just as portable as the ones that mindlessly follow the limited and bizarre POSIX shell spec. I'll write POSIXly-correct shell scripts…
The POSIX shell is the Bourne shell (1979) plus half of the innovations brought by ksh88.
The other half of the improvements from ksh88 and all of the improvements from ksh93 are not included in the POSIX shell standard.
Also for POSIX compliant shells one must not forget that also the other programs invoked by the shell must not be used with non-POSIX options.
For example, in a bash script I used the ksh93 syntax:
${VARIABLE:64:32}
Then I wanted to make it POSIX compliant and I rewrote it in the longer: $(expr substr "${VARIABLE}" 65 32)
But then I discovered that POSIX expr lacks substr, so I had to rewrite the expression into the even longer: $(awk -v s="${VARIABLE}" 'BEGIN {print substr(s, 65, 32)}')
which is the only POSIX compliant way to extract substrings.In most cases the rational way is to write scripts for bash or zsh, which include all the ksh93 features plus brace expansion (from csh, then enhanced by zsh).
Writing POSIX compliant scripts results in much longer scripts in which the chances of bugs are much higher.