Bash

我有多少貝殼?

  • July 2, 2017

問題:找出我有多少貝殼。

詳細資訊:我經常從 vim 打開 shell。建構並執行並退出。有時我會忘記並在裡面打開另一個vim,然後再打開一個shell。:(

我想知道我有多少貝殼,甚至可能一直在我的貝殼螢幕上。(我可以管理那部分)。

我的解決方案:解析程序樹並查找 vim 和 bash/zsh 並找出目前程序在其中的深度。

類似的東西已經存在了嗎?我什麼也找不到。

當我讀到你的問題時,我的第一個想法是$SHLVL。然後我看到你想計算除了shell 級別之外的級別vim。 一個簡單的方法是定義一個 shell 函式:

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

SHLVL 每次鍵入vim命令時,這將自動且無提示地遞增。您將需要為您曾經使用的vi/的每個變體執行此操作;vim例如,

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

外圓括號創建了一個子shell,因此手動更改 的值SHLVL 不會污染目前(父)shell 環境。當然,command關鍵字是為了防止函式呼叫自己(這將導致無限遞歸循環)。當然,您應該將這些定義放入您的.bashrc或其他 shell 初始化文件中。


上面有一點效率低下。在某些 shell 中(bash 是其中之一),如果你說

**(***命令1***;** *命令2***;** …… **;** *命令n***)**

where是一個外部的可執行程序(即,不是內置命令),shell 保留了一個額外的程序,只是等待終止。這(可以說)沒有必要;優點和缺點是有爭議的。如果您不介意佔用一點記憶體和一個程序槽(並且在執行 a 時看到比您需要的更多的 shell 程序),那麼請執行上述操作並跳到下一部分。如果您使用的外殼不會保留額外的程序,則同上。但是,如果你想避免額外的過程,首先要嘗試的是*cmdn*``*cmdn*``ps

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

exec命令用於防止額外的 shell 程序延遲。

但是,有一個問題。shell 的處理SHLVL有點直覺:當 shell 啟動時,它會檢查是否SHLVL已設置。如果未設置(或設置為非數字),則 shell 將其設置為 1。如果已設置(設置為數字),則 shell 將其加 1。

但是,按照這個邏輯,如果你說exec sh,你SHLVL應該上去。但這是不可取的,因為您的真實外殼級別沒有增加。外殼通過從 您執行以下操作時減去一個來處理此問題: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(他什麼都知道)的說法,一些 shell 足夠聰明,如果它位於子 shell 中,則不會這樣做exec

要解決這個問題,你會做

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

然後我看到你想獨立於shell 級別來計算級別vim。 好吧,完全相同的技巧有效(好吧,稍作修改):

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

(等等viview等)export是必要的,因為VILVL預設情況下未定義為環境變數。但它不需要成為函式的一部分;你可以說export VILVL作為一個單獨的命令(在你的.bashrc)。並且,如上所述,如果額外的 shell 程序對您來說不是問題,您可以command vim代替exec vim,而不要SHLVL理會:

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

個人偏好:

您可能想重命名VILVLVIM_LEVEL. 當我看“ VILVL”時,我的眼睛很痛;他們無法判斷這是“vinyl”的拼寫錯誤還是羅馬數字格式錯誤。


如果您使用的shell 不支持SHLVL(例如dash),您可以自己實現它,只要該shell 實現一個啟動文件。只是做類似的事情

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

在您.profile或適用的文件中。(您可能不應該使用名稱SHLVL,因為如果您開始使用支持 的外殼,那將導致混亂SHLVL。)


其他答案已經解決了將環境變數值嵌入到您的 shell 提示符中的問題,所以我不會重複這一點,尤其是您說您已經知道該怎麼做。

引用自:https://unix.stackexchange.com/questions/373704