現在のシェルインタプリタ名を*安定的に*簡単に*取得するにはどうすればよいですか?

現在のシェルインタプリタ名を*安定的に*簡単に*取得するにはどうすればよいですか?

私はスクリプトまたはソースファイルから現在のシェルの名前を取得する簡単で信頼性の高い方法を探しています(いいえコマンドラインから)。私はこれをしたかったのですが、$(basename "$SHELL")私のログインシェルがあり、zshsome_script.shに次のコードがある場合

this_shell=$( basename "$SHELL" )
echo "The Shell is $this_shell"
echo "The Shell is $0"

として実行したが、使用されたインタプリタがあったにもかかわらず、bash some_script.shまだリストされています。シェルデザイナーがなぜ現在のシェルの代わりにデフォルトのシェルを表示することを選択したのかはわかりませんが、それが私たちが固守しているようです。zshbash/bin/bash

もう少し似たような質問があります(ここそしてここ)、しかし彼らの答えは多くの点で欠けています。

  1. 彼らはしばしば、ユーザーが現在どのインタラクティブシェルを使用しているかを把握しようとしていると仮定していますが、これは不可能です。どのシェルにコマンドを入力するかを知っています。どのシェルを決定するには、どこでも実行できるコードが必要です。それ使用しています。
  2. 彼らはしばしばいくつかの異なる試みを提供します。コマンドラインのように、bashを使用していることがわかるまで、私はすべての状況で信頼できるものが必要でした。
  3. 彼らはしばしばスクリプトで完全に役に立たないものを提供しますecho $0。たとえば、上記のスクリプトに示すように失敗します。 (はい、インタラクティブシェルコマンドラインで動作しますが、どのシェルを使用しているのかわからないのはなぜですか?)
  4. 彼らは時々命令を出します(制限されたテストで)。含むなどの情報は正確ですps -p $$が、パイプを通過するためのクロスプラットフォーム、クロスシェル互換のsed / awkコマンドが不足しています。ただシェル名付属のその他のメッセージは無視してください。
  5. $BASH_VERSIONこれには、などのいくつかのシェルでのみ実行される項目が含まれます$ZSH_VERSIONfish、、、など、できるだけ多くのシェルをサポートしたいと思いますcshtcsh

私がどうする安定してそして精密発覚どの 現在のシェル?私はプラットフォーム、スクリプト、そしてできるだけ多くの合理的なシェルで動作することを探しています1。

修正する:この質問を投稿したとき、この情報を提供するためにシェルにいくつかの機能が組み込まれていると予想しましたが、そうではありません。今は何かに頼るのが避けられないようです。外のシェル、私が欲しいものはより具体的に言わなければなりませんでした。クロスプラットフォーム解決策(上記の他の答えに対する私の反対の投票はこれについてのヒントを与えますが、質問を注意深く読まないと見逃すことがあります)。

アップデート2 Stéphaneの答えはLinux専用ではないので、これがLinux専用の質問と重複していると思う人がいる場合は、ここで私が要求したものと彼が提供したものとの違いがあります。 (彼はそれを非常に賢く書いており、私はそれを叩いていませんが、それが私の問題を解決しないことに注意してください。)

  1. 私は何かを探しています。シンプルそして信頼できる、それ
  2. .zshrcすべてのスクリプトまたは関数定義(または.bash_profile他のソースによって分岐)に追加できます。
  3. 彼のスクリプトは常にデフォルトのインタプリタによって解釈され返されるので、インタプリタ名を呼び出しスクリプト/関数に渡す外部ユーティリティとしては使用できません。これは私の目的で使用するのが難しいか不可能になります。可能であれば、依然として非常に難しく、それを機能させる解決策は次のとおりです。いいえ答えに与えられました。だから彼は私の質問に答えなかったので、重複ではありません。

何か見たいなら〜する働いてみてGitHubのShellDetective。これにより、すでにSEにあるものと、この質問が探しているもの(実際に他の場所では満たされていないこの質問のニーズを満たすために書かれたもの)との違いを簡単に確認できます。


(PS、そのようなユースケースがあると思わない場合は、使用しているサーバーと利用可能なシェルに応じて、、またはでソースされる機能を想像してみてください。.zshrcその.bash_profile機能.profileはソースなのでshebangがありません。実行方法を知るには、どのシェルにあるかを知る必要があります。


1私は伝統的な意味では、シェルではなく「シェル」に興味がありません。私は誰かが自分で書いたシェルには興味がありません。私は興味があります本物の殻これは実際に実際に発生し、誰かが一部のサーバーにログインするときにこれを使用する必要があり、必要なシェルをインストールできない可能性があります。

答え1

この組み合わせで良い結果を得ました。

ps -p $$ | awk '$1 != "PID" {print $(NF)}'

Tru64(OSF / 1)では、出力のシェルの周りに括弧があります。tr -d '()'除去する接着剤です。

ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()'  

すべてのシェル、Solaris 10、RHEL 5.7/6.4で動作するようです。 Debian、Ubuntu、Mintなどの他のディストリビューションはテストしていませんが、すべて同じように動作する必要があるとします。 FreeBSDも動作するかもしれません。

ここに画像の説明を入力してください。

答え2

だから私はまだこれを具体化しようとしていますが、効果的なアイデアがあると思います。すでに知っているように、すべてのシェルで実行したいことは不可能ではなくても非常に困難です(ポリグロットに追加するすべての変形は、線形速度よりも大きい速度で複雑さを増やします)。 Bourne(sh、ash、dash、bash、ksh、pdksh、zshなど)とCスタイルシェル(csh、tcsh、fishな​​ど)に分割すると、おそらくこれが可能ですが、csh現在のバリエーション間の変更があります。多様で興味深い変化の挑戦。

したがって、既知の言語(bash、C、perl、pythonなどのshebang行を含む)で検出ルーチンを作成し、親実行可能ファイルの名前を決定します。その後、2つのトリックを使用して情報を親に返すことができます。つまり、戻り値と標準出力に書き込まれる単一の単語です。 shが削除されたシェルは0を返し、シェル名を書きます。なぜなら、すべてバックティック処理がうまくいくからです。 Cシリーズシェルでは、解決する必要がある各非互換性セットの戻り値の追加を開始できます。 200を超える戻り値はエラーを表し、最初はすべてが大丈夫に見えますが、200では両親が誰であるかわかりません。

内部手順はLinuxで簡単に見えます(/proc/ppid/exe戦闘の半分が勝ちます)。 psオプションを使用してbsdでこれを行うことができると確信していますが、現在テストしている実行中のbsdシステムがなく、私のMacには新しいハードドライブ(とにかく10.4のみ)が必要です。シェル構文の問題を大幅に軽減しますが、他の互換性の問題が発生します。私はまだ可能性があると思います。

答え3

これを試してください。

shell_bin=$(ps h -p $$ -o args='' | cut -f1 -d' ')
echo $shell_bin

答え4

これはどうですか、申し訳ありません。試してみるプラットフォームはあまりありません。

local __shell=`ps $$ -o comm=""`

関連情報