web-dev-qa-db-ja.com

kshのバージョンを安全に取得するにはどうすればよいですか?

Kshスクリプト内からkshのバージョンを安全に取得するにはどうすればよいですか?

私は 次の解決策を見た

  1. ksh --version
  2. echo ${.sh.version}
  3. 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_VERSIONpdkshによってのみ設定されます。

質問:

  • kshのバージョンをプログラムで安全に確認するにはどうすればよいですか?ここでの目的のために、実際のバージョン番号が何であるかは気にしません。それがkshの古いバージョンかどうかだけです。
  • $KSH_VERSIONで十分ですか?空白の場合、kshは必ずしも古いバージョンですか? kshの新しいバージョンでも設定されない可能性があるという他のフォーラムは正しかったですか?
  • これをチェックする方法はまったくありませんか?
12
Sildoreth

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
_
2
Sildoreth

.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では実装されていませんでした。 mkshpdkshlkshに設定されます。 kshのバージョンを確認するために、次の手順を試すことができます。

  • mkshpdkshlkshを検出するためにKSH_VERSIONをチェックしています
  • 最初のステップが失敗する場合は、ksh93ksh88/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
6
cuonglm

「実際の」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/mshkshクローンと最新の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ではテストされていません。

5
jlliagre

CTRL+ALT+V

または

ESC 、 CTRL+V

使用しているKSHのバージョンを対話的に決定する限り、通常は非常に信頼できることが証明されていますが、それらをスクリプト化することはより困難であることが証明されています。

1
Tim Kennedy

以下は、古い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"
0
Greg A. Woods

$ {。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で実行しました。

ピート

0
Pete