Shell Script – Safely Get Version of Ksh

kshportabilityshell-scriptversion

How can I safely get the version of ksh from within a ksh script?

I have seen the following solutions:

  1. ksh --version
  2. echo ${.sh.version}
  3. echo $KSH_VERSION

And given the right circumstances, each of these works correctly. However, I care about the non-perfect case.

Specifically, there are several machines I work with that have older versions of ksh that, for my purposes, are severely lacking in functionality. Anyway, the reason I want to check the version (programmatically) is to see if the ksh version is one of the less capable versions; and if so, I want to execute a branch with less awesome code.

However, on the problematic machines, the shell's ineptitude extends into checking the version…

  • If I try ksh --version, it prints nothing and opens a new instance of ksh!
  • If I try echo ${.sh.version}, ksh treats this as a syntax error that cannot be discarded with 2> /dev/null.

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
    
  • Of course echo $KSH_VERSION appears to work fine – I mean it won't crash – though on these machines it's blank. Also, I saw somewhere that KSH_VERSION is set only by pdksh.

Questions:

  • How can I safely check the version of ksh programmatically? For my purposes here, I don't really care what the actual version number is, just whether it's an outdated version of ksh.
  • Is $KSH_VERSION good enough? I mean if it's blank, then is ksh necessarily an outdated version? Was that other forum correct that it might not be set even for newer versions of ksh?
  • Is there just no way to check this at all?

Best Answer

KSH_VERSION was not implemented in ksh93 before version 93t. It will be set in mksh, pdksh, lksh. So for checking the version of ksh, we can try these steps:

  • Checking KSH_VERSION to detect mksh, pdksh, lksh
  • If first step fails, try a feature that's different between ksh93 and ksh88/86 (Let David Korn show us).

With these in mind, I will go with:

case "$KSH_VERSION" in
  (*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
  (*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac
Related Question