ZSH 中的变量作用域:如何从函数内访问全局变量?

ZSH 中的变量作用域:如何从函数内访问全局变量?

我有一个不断扩大的.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 全局变量可以从另一个函数的范围内访问,但不将这些值作为参数传递?

根据这个答案经过吉尔斯“所以——别再作恶了”...

export[in] zsh 是 的简写typeset -gx,其中属性g表示“全局”(与函数的本地相对),属性x表示“导出”(即在环境中)。

...因此我假设该$NVM_DIR变量应该可以从另一个函数中使用。

答案1

您的函数将看到您之前设置的变量(无论是否导出),前提是它们尚未在子 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"显然不是空字符串,因此无论 的值如何, test 都会返回 true $config_file。所以你的循环不会做任何事情。

您的意思可能是类似 的东西[[ $config_file = .zsh(rc|env) ]],尽管这有点毫无意义,因为它们$config_file永远不会是.zshrc.zshenv是隐藏文件,因此默认情况下不包含在全局扩展中,并且无论如何$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 varlocal

function {
  local var
  ...
}

如果有$var来自外部作用域(或来自环境)的 a ,那么将不理会它,而不是最终取消它。

相关内容