Kshスクリプト内からkshのバージョンを安全に取得するにはどうすればよいですか?
私は 次の解決策を見た :
ksh --version
echo ${.sh.version}
echo $KSH_VERSION
そして、適切な状況では、これらはそれぞれ正しく動作します。しかし、私は完全ではないケースを気にします。
具体的には、私が使用するいくつかのマシンで古いバージョンのkshが使用されていますが、私の目的では、機能が大幅に不足しています。とにかく、バージョンを(プログラムで)チェックしたいのは、kshバージョンが機能の低いバージョンの1つであるかどうかを確認するためです。もしそうなら、私はそれほど素晴らしいコードでブランチを実行したいと思います。
ただし、問題のあるマシンでは、シェルの不適性がバージョンのチェックにまで及んでいます...
ksh --version
を試しても何も表示されず、ksh
の新しいインスタンスが開きます。echo ${.sh.version}
を試すと、ksh
はこれを2> /dev/null
で破棄できない構文エラーとして扱います。
$ echo ${.sh.version} 2> /dev/null
ksh: ${.sh.version}: bad substitution
もちろん、echo $KSH_VERSION
は問題なく動作するように見えます(つまり、クラッシュしないことを意味します)。これらのマシンでは空白です。また、私は どこか を見ましたKSH_VERSION
はpdksh
によってのみ設定されます。
質問:
ksh
のバージョンをプログラムで安全に確認するにはどうすればよいですか?ここでの目的のために、実際のバージョン番号が何であるかは気にしません。それがksh
の古いバージョンかどうかだけです。$KSH_VERSION
で十分ですか?空白の場合、ksh
は必ずしも古いバージョンですか? ksh
の新しいバージョンでも設定されない可能性があるという他のフォーラムは正しかったですか?ksh
のスクリプトを書いているときに、kshの組み込みwhence
コマンドの_-a
_オプションが、古いバージョンのksh
ではサポートされていないように見えることに気付きました。これは、Solaris、AIX、HP-UX、Linuxを含む、私がチェックしたすべてのシステムに当てはまるようです。
だからここにksh関数としての解決策があります:
_is_modern_ksh() {
if whence -a whence > /dev/null 2>&1 ; then
return 0 #success -> true
fi
#Else the call to `whence` failed because `-a` is not supported
return 1 #failure -> false
}
_
そして、それを使用する方法は次のとおりです。
_if is_modern_ksh ; then
echo "You're using a MODERN version of ksh. :)"
else
echo "You're using an OLD version of ksh. :("
fi
_
.sh.version
は、ATT ksh 93の最初のバージョンから存在しています。pdkshまたはmkshでは使用できません。 ${.sh.version}
はksh93以外のシェルでの構文エラーです。テストはサブシェルでラップし、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
パブリックドメインのkshクローン(pdksh)で始まり、ksh93tを使用して2008年に比較的最近に実際のKornシェルに追加されました。
バージョン番号をテストするのではなく、悲しみを与えている特定の機能をテストする必要があります。ほとんどの機能は、サブシェルでいくつかの構成を試し、エラーが発生するかどうかを確認することでテストできます。
KSH_VERSION
は、バージョン93tより前のksh93
では実装されていませんでした。 mksh
、pdksh
、lksh
に設定されます。 ksh
のバージョンを確認するために、次の手順を試すことができます。
mksh
、pdksh
、lksh
を検出するためにKSH_VERSION
をチェックしていますksh93
とksh88/86
の間で異なる機能を試してください( Let David Kornに見せてください )。これらを念頭に置いて、私は一緒に行きます:
case "$KSH_VERSION" in
(*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
(*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac
「実際の」ksh
リリース(つまり、AT&Tベース)では、次のコマンドを使用します。
strings /bin/ksh | grep Version | tail -2
ここに私が得る様々な出力があります:
元のksh:
@(#)Version M-11/16/88i
dtksh;
@(#)Version 12/28/93
Version not defined
最新のksh93:
@(#)$Id: Version AJM 93u+ 2012-08-01 $
pdksh
/msh
ksh
クローンと最新のAT&T ksh
バージョンの場合も、次のように機能します。
$ mksh -c 'echo $KSH_VERSION'
@(#)MIRBSD KSH R50 2015/04/19
編集:
テストしたkshバイナリへのパスを知らないで、スクリプトの内部からそれを行うことについてあなたが尋ねているのを見逃しました。
使用するksh
のバージョンではなく、サポートする機能が本当に必要だとすると、少なくともLinuxとSolarisで動作するstrings
コマンドのみを使用して、これを行う1つの方法を次に示します。
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)
/proc
がマウントされていない可能性があるため、この方法は信頼性が低く、他の弱点も確かにあることに注意してください。他のUnix OSではテストされていません。
CTRL+ALT+V
または
ESC 、 CTRL+V
使用しているKSHのバージョンを対話的に決定する限り、通常は非常に信頼できることが証明されていますが、それらをスクリプト化することはより困難であることが証明されています。
以下は、古いksh88eとほぼ完全な共通のKshクローン(それぞれの1つのバージョンのみ)を含む)を含め、私がテストしたすべてのシェルで適切に機能するようですが、実際のオリジナルのBourne Shellはまだテストしていません(そのためには、古いバージョンのtest
式を調整する必要があるかもしれません...
補遺:
私はこれをHeirloom Bourne Shellでも正常にテストしましたが、外部(そしてより近代的な)test
プログラムを使用しました。
is_attksh()
{
# ksh93
_sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null)
# pdksh only
_opt_login=$(set -o | grep login)
test -n "${_sh_version}" -o \( -z "${_opt_login}" -a -n "${_}" -a -n "${ERRNO}" -a -n "${FCEDIT}" -a -n "${PS3}" \)
}
is_attksh && echo "AT&T Ksh${_sh_version:+: }${_sh_version:- (probably ksh88 or ksh86)}" || echo "not real ksh"
is_zsh()
{
test -n "${ZSH_VERSION}"
}
is_zsh && echo "Zsh: ${ZSH_VERSION}" || echo "not zsh"
$ {。sh.version}を使用することの根本的な問題は、ksh88がゼロ以外の終了コードで停止することです。
したがって、私の解決策は、サブシェルに$ {。sh.version}を参照するコードを配置し、サブシェルがゼロ以外で終了するかどうかをテストし、バージョンで動作するコードをサブシェルに含めることです$ {。sh.version}を参照するkshは機能します。これを関数にラップしてから、戻りコードを逆にする別の関数によって呼び出されるので、最後の呼び出しはtrueかどうかをチェックします。
function is_oldksh
{
(test -n ${.sh.version}) 2>/dev/null
}
function oldkshtest
{
is_oldksh || return 0 && return 1
}
oldkshtest && echo "old ksh" || echo "new ksh"
私はこれを、AIXとOracle Enterprise Linux 5&6、ksh88、ksh93、pdkshで実行しました。
ピート