Zsh

ZSH 中的變數範圍:如何從函式內訪問全域變數?

  • April 27, 2022

我有一個不斷擴大的.zshrc文件,已經失控,所以我決定嘗試通過將其分解為模組化文件並採購每個文件來修復它。這在大多數情況下都有效,但我似乎有一些與變數相關的範圍問題。

每個模組文件都包含一個與文件名對應的函式匹配。例如:nvm..zshrc包含.zshrc名為zshrc_config_load_nvm {}.

下面是我正在使用的設置的簡化形式。

主 .zshrc 文件

請注意,我已經徹底測試了這個文件,其中的所有內容都執行良好。

# Load all config files 
# This method basically copied directly from the .oh-my-zsh.sh file.
for config_file ($ZSH_CUSTOM/*.zshrc(N)); do

   # Skip self-inclusion
   if [[ $config_file==".zshrc" || $config_file==".zshenv" ]]; then
       continue
   fi
   
   # The (D) modifier will escape the path so it can be passed to `basename`
   # without quotes. the second param in `basename` removes the file extension.
   local handle=$(basename ${(D)config_file} .zshrc)

   # If the file contains the expected callback function name ...
   # The :t filter will remove the path and file extension.
   if [[ $(command -v "zshrc_config_load_${handle}") ]]; then
       
       # ... Add it to the list of functions to call.
       ZSH_CONFIG_HANDLES+=($handle)
   fi
   # Each config file will call the register function above.
   source $config_file
done

for handle ($ZSH_CONFIG_HANDLES); do

   func="zshrc_config_load_${handle}"

   # Call the function
   $func
done
unset config_file handle func

nvm.zshrc

# This line is copied directly from the documentation. 
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"



# The callback function
function zshrc_config_load_nvm {
   
   # Unable to access the $NVM_DIR variable in this scope. 
   source $NVM_DIR/nvm.sh --fast-reuse
   # Error: /nvm.sh does not exist.
}

問題

如何使exported 全域變數可以從另一個函式的範圍內訪問,但不將這些值作為參數傳遞?

根據Gilles 的這個回答, “所以,不要再作惡了” ……

export

$$ in $$zsh 是 的簡寫typeset -gx,其中屬性g表示“全域”(相對於函式的局部),屬性x表示“導出”(即在環境中)。

…因此我假設該$NVM_DIR變數應該在另一個函式中可用。

您的函式將看到您之前設置的變數(以及是否導出),前提是它們尚未在子 shell 中設置或未聲明為某個已返回的函式的本地變數。

您的問題來自程式碼中不相關的錯誤:

for config_file ($ZSH_CUSTOM/*.zshrc(N)); do

    # Skip self-inclusion
    if [[ $config_file==".zshrc" || $config_file==".zshenv" ]]; then
        continue
    fi

[[ somestring ]]``somestring如果不是空字元串,則返回 true 。$config_file==".zshrc"顯然不是空字元串,因此無論$config_file. 所以你的循環不會做任何事情。

您可能的意思是類似[[ $config_file = .zsh(rc|env) ]],儘管這有點毫無意義,因為它們$config_file永遠不會.zshrc.zshenv隱藏文件,因此預設情況下不包含在 glob 擴展中,並且無論如何$config_file也以/path/to/zsh_custome/(並且.zshenv不以 結尾.zshrc)開頭。

if [[ $config_file -ef $0 ]] continue檢查這$config_file不是目前正在獲取的腳本可能更有意義。

其他注意事項:

 export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"

最好寫成:

if (( $+XDG_CONFIG_HOME )); then
 export NVM_DIR=$XDG_CONFIG_HOME/nvm
else
 export NVM_DIR=~/.nvm
fi

在:

  local handle=$(basename ${(D)config_file} .zshrc)

D參數擴展標誌(例如轉向)/home/you/file沒有~/file意義。

聽起來像你想要的local handle=$config_file:t:r(文件尾部的**根)。

  if [[ $(command -v "zshrc_config_load_${handle}") ]];

最好寫成:

if command -v "zshrc_config_load_${handle}" >& /dev/null;

這避免了叉子。或者可能if (( $+functions[zshrc_config_load_${handle}] ));

代替做var=...unset var,您可以local在函式或匿名函式中使用:

function {
 local var
 ...
}

如果有$var來自外部範圍(或來自環境)的 a,那麼它將不理會它,而不是最終取消它。

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