How can I safely get the version of ksh?
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 detectmksh
,pdksh
,lksh
- If first step fails, try a feature that's different between
ksh93
andksh88/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
I think that .sh.version
has existed ever since the first version of ATT ksh 93. It isn't available in pdksh or mksh. Since ${.sh.version}
is a syntax error in shells other than ksh93, wrap the test for it in a subshell and protect it behind eval
.
_sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null) 2>/dev/null
case $_sh_version in
'') echo "This isn't ATT ksh93";;
…
esac
KSH_VERSION
started out in the public domain ksh clone (pdksh), and was added to the actual Korn shell relatively recently, in 2008 with ksh93t.
Rather than test for a version number, you should test for the specific feature that's giving you grief. Most features can be tested for by trying some construct in a subshell and see if it triggers an error.
For "real" ksh
releases (i.e. AT&T based), I use this command:
strings /bin/ksh | grep Version | tail -2
Here are various output I get:
Original ksh:
@(#)Version M-11/16/88i
dtksh;
@(#)Version 12/28/93
Version not defined
Modern ksh93:
@(#)$Id: Version AJM 93u+ 2012-08-01 $
For pdksh
/msh
ksh
clones and modern AT&T ksh
versions too, here is something that works:
$ mksh -c 'echo $KSH_VERSION'
@(#)MIRBSD KSH R50 2015/04/19
Edit:
I overlooked you were asking about doing it from inside a script, not by knowing the path to the tested ksh binary.
Assuming you really want the version of ksh
used, and not the features it supports, here is one way to do it using only the strings
command that should work on at least on Linux and Solaris:
echo $(for i in $(find /proc/$$ ! -type d ! -name "pagemap" |
grep -v "/path/" | grep -v "/fd/" ) ; do
strings $i | egrep "([V]ersion|[K]SH_VERSION).*[0-9]" | sort -u
done 2>/dev/null)
Note that this method is unreliable as /proc
might not be mounted, and there are certainly other weaknesses. It is untested on other Unix OSes.