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


12

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_VERSIONのみで設定されているがpdksh

質問:

  • kshプログラムでバージョンを安全に確認するにはどうすればよいですか?ここでの目的のために、実際のバージョン番号が何であるかは気にしませんksh。それがの古いバージョンであるかどうかだけです。
  • $KSH_VERSION十分に良いですか?空白の場合、ksh必然的に古いバージョンですか?他のフォーラムは正しいのkshですか?
  • これを確認する方法はまったくありませんか?

1
優れたコードが少ない単一のパスではなく、2つのコードパスが必要な理由はありますか?
トールビョーンラヴンアンデルセン

@ThorbjørnRavnAndersenはプロンプトに関係しています。.kshrcファイルには、tcshおよびzshプロンプトのpwd短縮機能をシミュレートする関数があり、PS1この関数を使用するように設定しています。ただし、Old kshはではサポート$()していませんPS1。したがって、kshの最新バージョンのPS1場合、作成した関数を使用します。古いバージョンの場合、を使用し$PWDます。
シルドレス

さて、あなたは可能性があり(おそらく、一方が他方から生成)をお使いのコンフィギュレーション・ファイルの2つのバージョンがあり、その後、問題のマシンに適切なバージョンを配布しますか?
トールビョーンラヴンアンデルセン

別のアプローチは、単に「問題があるのはこの特定のマシンだけです-ここにのみ存在するファイルまたは環境変数または何か(おそらくAIXまたは何か)を見つけて、代わりにテストする」ことです。
トールビョーンラウンアンデルセン

回答:


7

.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)で始まり、比較的最近、2008年にksh93tで実際のKornシェルに追加されました。

バージョン番号をテストするのではなく、悲しみを与えている特定の機能をテストする必要があります。ほとんどの機能は、サブシェルでいくつかのコンストラクトを試し、エラーをトリガーするかどうかをテストすることでテストできます。


サブシェルを使用しても違いは見られません。それでも、${.sh.version}調整できない構文エラーとして扱います。私が受け取るメッセージはbad substitutionです。
シルドレス

@silサブシェルを使用するポイントは、エラーをキャッチすることです。エラーをリダイレクトし/dev/null、終了ステータスを無視します。
ジル 'SO-悪であるのをやめる'

私はあなたが言っていることを理解しています。私が言っているのは、エラーがリダイレクトされないということです。それは、常にコンソールに出力します。これをSolaris、AIX、およびHP-UXで試しました。また、kshはすべてでこの動作を示します。
シルドレス

@シルドレスああ。私はLinuxでしかテストしていませんでしたが、現在テストするこれらのOSはありません。eval '_sh_version=$(echo "${.sh.version}")' 2>/dev/nullうまく機能しますか?
ジル「SO-悪であるのをやめる」

それは少し良いです。SolarisおよびHP-UXで完全に機能します。AIXの場合、コマンドラインで動作しますが、シェル関数に配置しようとすると不思議なことに失敗し始めます。
シルドレス

6

KSH_VERSIONksh93バージョン93tより前では実装されていませんでした。これは、に設定されますmkshpdkshlksh。のバージョンを確認するにはksh、次の手順を試してください。

  • チェックKSH_VERSIONを検出するためにmkshpdkshlksh
  • 最初のステップが失敗した場合、との間ksh93で異なる機能を試してくださいksh88/86David 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_VERSION最初に空白でないかどうかをチェックしないのはなぜですか?私のUbuntuマシンでは、これは「ksh93」KSH_VERSIONと表示されますが、設定されています。
シルドレス

以前に実行されたコード(例:.kshrc)がランダム値でKSH_VERSION変数を改ざんした場合、これは失敗します。
jlliagre

@jlliagre:いいえ、スクリプトとして実行されたため、読み取りません.kshrc
クオンルム

ENV変数が設定されている場合(通常はに設定されている場合~/.kshrc)、スクリプトは間違いなく.kshrcファイルを読み取ります。もちろん、スクリプトが偽のKSH_VERSIONを設定することは非常に奇妙ですが、それでも可能です。最初の行で指定されたものとは異なるインタープリターでスクリプトを明示的に実行するのと同様です。
jlliagre

@jlliagre:変更することもできますが、を参照するとセグメンテーション違反が発生しますKSH_VERSION。そして、でmkshpdkshlkshKSH_VERSION読み取り専用としてマークされています。
クオンルム

5

「実際の」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サポートされている機能ではなく、使用するバージョンが本当に必要な場合strings、少なくともLinuxとSolarisで動作するコマンドのみを使用して実行する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ではテストされていません。


これは区別されませんlkshし、pdkshDebianのジェシーに。
クオンルム

@cuonglm私はテストするジェシーがいません。あなたが意味するかlkshpdksh自分から選別することはできませんかKSH_VERSION
jlliagre

いいえ、私はstrings彼らの上で走ることを意味します。KSH_VERSION間違いなくできます。
クオンルム

@cuonglm不明な場合は申し訳ありません。「実際の」kshリリース用に«を書いたときpdksh、のようなAT&T以外のkshクローンを明示的に除外mkshしていましたlksh
jlliagre

stringsいくつかのkshバイナリで実行することは、それがスクリプトを実行しているのかどうかわからないため、悪い考えです。たぶんあなたのスクリプトは/usr/local/bin/kshor /home/bob/bin/kshまたは/bin/shor /usr/posix/bin/shor によって実行されています…
Gilles「SO-悪であるのを止めてください」

2

のスクリプトを書いていたkshときに-a、kshの組み込みwhenceコマンドのオプションがの古いバージョンでサポートされていないように見えることに気付きました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}か?
クオンルム

@cuonglmできないから。Gillesの回答に関するコメントを参照してください。
シルドレス

残念ながら、whenceZshには-a
グレッグA.ウッズ

@ GregA.Woods、この関数はksh専用です。関数定義は.kshrcに格納されるため、zshなどの他のシェルにも存在しません。zshには独自の組み込みwhenceコマンドがあり、kshまたはそのバージョンとは一切関係ありません。まったく異なるシェルであるzshのインスタンス内からkshが古いバージョンであるかどうかを確認する理由がわからない。
シルドレス

あなたの仮定に問題があります:Zshはしばしば/bin/kshDebian Linuxのようなへのリンクでインストールされます。今はここでは使用せず(また、現時点ではチェックするためにログインシェルを変更することはできません)、読み取り.kshrcかどうかはわかりませんが、そうなると思います。
グレッグA.ウッズ

1

CTRL+ ALT+V

または

ESCCTRL+V

使用しているKSHのバージョンをインタラクティブに決定する限り、通常は非常に信頼性が高いことが証明されていますが、スクリプトを作成することはより困難です。


1
これは、AIX ksh 88fバージョンで機能する唯一のものでした。
ジェフシャラー

1
set -o viキーバインドをviのように設定して実行した後、<kbd> ESC </ kbd>、<kbd> CTRL </ kbd> + <kbd> V </ kbd>オプションが動作するようになりました。その前、または+ o viまたは-o emacsを使用すると、単に表示されません。PD KSH v5.2.14 99/07 / 13.2 on openbsd 6.1
bgStack15

0

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

ピート


1
最新のAT&T Kshはまだ提供しています.sh.version(実際にKSH_VERSIONは事実上のエイリアスです)。また、NetBSD shなどの一部のシェルは、遭遇する${.sh.version}と読み取りを停止するだけで、スクリプトを実行し続けるリダイレクトの量はありません。
グレッグA.ウッズ

0

以下は、古いksh88eとほぼ完全な範囲の一般的なKshクローン(それぞれのバージョンは1つだけです)を含め、テストしたすべてのシェルで十分に機能するようです(実際のオリジナルのBourneシェルはまだテストしていません(そのためには、 test、古いバージョンに式をます。...

補遺:

また、外部(より最新の)testプログラムを使用していますが、Heirloom Bourne Shellでこれを正常にテストしました。

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"

kshではないシェルに対してこの関数を実行する理由は何ですか?bashまたはzshでスクリプトを実行している場合、kshは決して機能しません。さらに、${.sh.version}kshの特定のバージョン(元の投稿が懸念していたバージョン)がその構文で致命的なエラーを起こすため、ソリューションの一部になれない他の回答によって既に確立されています。
シルドレス

私が言ったように、私が示す機能は、「致命的な」エラーを出すkshのバージョンと、同じことをするAshのバージョンでテストされています。
グレッグA.ウッズ

私が書いたスクリプトは、移植可能であり、任意の有能なシェルによって実行されることを意図しています。また、別の場所で言ったように、「ksh」と入力するとZshバイナリが(argv [0]を「ksh」として)起動されるため、一部の人はZshをKshとして使用していることを必ずしも知らないでしょう。
グレッグA.ウッズ

それはあなたがどこから来ているのかを明らかにします。しかし、それは非現実的な要件のように聞こえます。通常、Unix開発者が「ポータブル」と言うとき、「このコードはどのシェルでも実行される」という意味ではなく、「これはどのシステムでも実行される」という意味です。また、別のシェル用に作成されたスクリプトを実行する必要がある場合、それは完全に合法です。スクリプト内の他のシェルの非対話型インスタンスを開始するだけです。良いコーディング慣行を促進したいので、これを取り上げます。このソリューションがあなたのために働くなら、素晴らしい。しかし、私は他の人にもっと簡単なアプローチを取ることを勧めます。
シルドレス

1
確かに、後方互換性を過去に引きずり込む努力はかなり馬鹿げています。古代のAT&T KshとUnix Shのバージョンをコンパイルしただけで、いくつかの機能の歴史と進化をよりよく理解し、物事がどのようになっていたかの記憶をリフレッシュしたいという自分自身の欲求を満たします私が覚えているよりも良い」、しかしいつか彼らはもっとひどかった)。
グレッグA.ウッズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.