私の殻の深さは何人ですか?

私の殻の深さは何人ですか?

質問:私が持っている殻が何個あるのか調べてください。

詳細:私はしばしばvimでシェルを開きます。ビルドして実行して終了します。時には別のvimを開いて別のシェルを開くのを忘れることがあります。 :(

私のシェルがどれほど深いか知りたいです。たぶん私のシェル画面に深く入るかもしれません。 (その部分は私が管理できる。)

私のソリューション:プロセスツリーを解析し、vimとbash / zshを見つけて、現在のプロセスがどれほど深いかを調べます。

似たようなものはすでに存在していますか?何も見つかりません。

答え1

あなたの質問を読んだときに最初に考えたことはありました$SHLVL。それからvimレベルを計算したいのを見ました。またシェルレベル。簡単な方法はシェル関数を定義することです。

vim()  { ( ((SHLVL++)); command vim  "$@");}

SHLVL コマンドを入力するたびに、値は自動的に自動的に増加しますvim。たとえば、/を使用したviすべてのバリアントに対してこれを行う必要があります。vim

vi()   { ( ((SHLVL++)); command vi   "$@");}
view() { ( ((SHLVL++)); command view "$@");}

外側の括弧グループはサブシェルを作成するため、値を手動で変更してもSHLVL 現在の(親)シェル環境は汚染されません。もちろん、commandキーワードの目的は、関数が自分自身を呼び出すのを防ぐことです(これにより無限再帰ループが発生します)。もちろん、これらの定義を自分.bashrcまたは他のシェル初期化ファイルに入れる必要があります。


上記は少し非効率的です。一部のシェルでは(bashがそのうちの1つです)、

コマンド1; コマンド2;; コマンドn)

外部実行プログラムの場合(つまり、組み込みコマンドではない)、シェルは終了を待つ追加のプロセスを維持します。これは(おそらく)不要です。長所と短所は議論の余地があります。少しのメモリとプロセススロットを占有しても大丈夫であれば(そしてそのタスクを実行するときに必要以上のシェルプロセスが表示される場合)、上記のタスクを実行して次のセクションに進んでください。追加のプロセスを維持しないシェルを使用する場合は、上記と同じです。しかし、追加のプロセスを避けたい場合は、最初に試してみてくださいcmdncmdnps

vim()  { ( ((SHLVL++)); exec vim  "$@");}

このexecコマンドの目的は、追加のシェルプロセスが移動するのを防ぐことです。

しかし、問題があります。シェルの処理はやや直感的です。シェルが起動したら設定されていることをSHLVL確認してください。SHLVL設定されていない場合(または数値以外の値に設定されている場合)、シェルはこれを1に設定します。設定すると(数値で設定)、シェルはそれを1ずつ増やします。

だがその論理によれば'といえば上がらなければならないexec shSHLVL実際のシェルレベルは増加しないので、これはお勧めできません。シェルはこの問題を次のように処理します。マイナス1~から SHLVL 以下を行うときexec

$ echo "$SHLVL"
1

$ set | grep SHLVL
SHLVL=1

$ env | grep SHLVL
SHLVL=1

$ (env | grep SHLVL)
SHLVL=1

$ (env) | grep SHLVL
SHLVL=1

$ (exec env) | grep SHLVL
SHLVL=0

だから

vim()  { ( ((SHLVL++)); exec vim  "$@");}

それは洗濯です。SHLVL再び減少するためだけに増加します。vim機能の利点がなくても、そう言うこともできます。

メモ:
すべてを知っているStéphane Chazelasによると、いくつかの殻は十分にスマートです。いいえexecサブシェルにいる場合は、これを行います。

この問題を解決するには、次の手順を実行します。

vim()  { ( ((SHLVL+=2)); exec vim  "$@");}

vimそれからレベルを計算したいのを見ました。独立シェルレベル。まあ、同じトリックが動作します(少しだけ修正してください)。

vim() { ( ((SHLVL++, VILVL++)); export VILVL; exec vim "$@");}

vi(forなどview)はデフォルトでは環境変数として定義されていないため、export必須です。しかし、関数の一部である必要はありません。別のコマンドでVILVL話すことができます(あなたのコマンドで)。そして、上記のように追加のシェルプロセスが問題にならない場合は、次のことを実行できます。export VILVL.bashrccommand vimexec vimSHLVL

vim() { ( ((VILVL++)); command vim "$@");}

個人的な好み:
VILVL同様の名前に変更することもできますVIM_LEVEL。 「」を見るとVILVL目が痛いです。 「vinyl」のスペルが間違っているのか、ローマ数字の間違いなのかはわかりませんでした。


使用しているシェルがそれをサポートしていない場合SHLVL(ダッシュなど)、シェルが起動ファイルを実装している限り、直接実装できます。ただ次のようにしてください

if [ "$SHELL_LEVEL" = "" ]
then
    SHELL_LEVEL=1
else
    SHELL_LEVEL=$(expr "$SHELL_LEVEL" + 1)
fi
export SHELL_LEVEL

あなた.profileまたはそのファイルに。 (SHLVLサポートされているシェルを使用し始めると混乱を招く可能性があるため、namesを使用しないでくださいSHLVL。)


他の回答では、すでに環境変数の値をシェルプロンプトに含めるという問題に対処しているので、特にこれを行う方法を既に知っていると述べたので繰り返しません。

答え2

セッションリーダーが見つかるまでプロセスツリーを検索するのにかかる回数を数えることができます。zshLinuxと同様に:

lvl() {
  local n=0 pid=$$ buf
  until
    IFS= read -rd '' buf < /proc/$pid/stat
    set -- ${(s: :)buf##*\)}
    ((pid == $4))
  do
    ((n++))
    pid=$2
  done
  echo $n
}

またはPOSIXly(しかしそれほど効率的ではありません):

lvl() (
  unset IFS
  pid=$$ n=0
  until
    set -- $(ps -o ppid= -o sid= -p "$pid")
    [ "$pid" -eq "$2" ]
  do
    n=$((n + 1)) pid=$1
  done
  echo "$n"
)

これは、ターミナルエミュレータまたはgettyによって開始されたシェルに対して0を提供し、各サブアイテムに対して1を提供します。

起動時に一度だけ実行できます。たとえば、

PS1="[$(lvl)]$PS1"

あなたまたはそれに対応するコンテンツの~/.zshrcプロンプトにそれを含めます。

tcshそして、他のいくつかのシェル(zsh、、、少なくとも)は起動時に増加ksh93する変数を保持します(そして他のコマンドを実行する前に減少します(サブシェルにエラーがない場合(しかし多くの場合エラーが発生した場合)は除く)) 。数量のみを追跡します。fishbash$SHLVLexecexecシェルただし、入れ子になったプロセスではなく、入れ子になったプロセスです。また、レベル0がセッションリーダーになることもできません。

答え3

使用echo $SHLVL。使用キスの原理。プログラムの複雑さによっては、これで十分かもしれません。

答え4

最初の変形 - シェルの深さのみ。

簡単な解決策bash.bashrc次の2行に追加します(または現在のPS1値を変更します)。

PS1="${SHLVL} \w\$ "
export PS1

結果:

1 ~$ bash
2 ~$ bash
3 ~$ exit
exit
2 ~$ exit
exit
1 ~$

プロンプト文字列の先頭の数字はシェルレベルを表します。

2番目のバリエーションには、入れ子になったvimレベルとシェルレベルの両方があります。

この行を次に追加します。.bashrc

branch=$(pstree -ls $$)
vim_lvl=$(grep -o vim <<< "$branch" | wc -l)
sh_lvl=$(grep -o bash <<< "$branch" | wc -l)
PS1="v:${vim_lvl};s:$((sh_lvl - 1)):\w\$ "
export PS1

結果:

v:0;s:1:/etc$ bash
v:0;s:2:/etc$ bash
v:0;s:3:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:1;s:4:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:2;s:5:/etc$ bash
v:2;s:6:/etc$

v:1 - vim 深さレベル
s:3 - シェル深さレベル

関連情報