首页 > 解决方案 > zshrc 无法识别自定义 bash 函数

问题描述

我最近从 bash 转到 zsh,和大多数人一样,我有我的自定义 bash 别名/函数来简化 git 和 env 采购操作。特别是其中有 2 个在 zsh 上运行时不能正常工作,但在 bash 上工作完全正常。

export REPO_ROOT=/home/pablo/repos/my_repo
alias croot='cd $REPO_ROOT'
alias subroot='cd $REPO_ROOT/subrepo/subrepo_1/'

repcheckout(){
 git checkout "$1"
 if [ $(pwd) == $REPO_ROOT ];  then
   subroot
 else
   croot
 fi
 git checkout "$1"
 if [ $(pwd) == $REPO_ROOT ];  then
   subroot
 else
   croot
 fi
}

这个想法是我有一组 main_repo-submodule 分支,当我签出主仓库时,我想签出相应分支中的子模块,而不是这样做:

$ git submodule update --init --recursive subrepo/subrepo_1

它检查了子模块中的正确提交,但没有更新我切换到某个本地分支。

前面的func,运行时zsh丢的错误

$ repcheckout my_cool_branch

M       subrepo/subrepo_1/
Switched to branch 'my_cool_branch'
repcheckout:2: = not found

后来我有一个 setup.sh 文件,我来源如下:

add2path() {
    if ! echo ${!1} | egrep "(^|:)$2(:|\$)" > /dev/null ; then
    declare -g $1="${!1}:$2"
    export "$1"
    fi
}

# GENERATED BINARY A
export BIN_A_HOME="$REPO_ROOT/bin_a"
add2path PATH "$BIN_A_HOME/bin"

与使用相同 add2path 添加到 PYTHONPATH 的一些生成的 python 模块相同

这会导致错误:

add2path:1: bad substitution 

标签: bashgitzsh

解决方案


这两个函数都使用在 zsh 中无效的 bashism。

repcheckout中,问题在于==在测试中使用运算符[ ]——标准运算符是=,但 bash 允许==作为同义词;zsh 没有。我还建议双引号两个字符串以避免路径中出现奇怪字符的问题(并且可能使用"$PWD"而不是$(pwd)):

if [ "$PWD" = "$REPO_ROOT" ];  then

在中,问题是和命令中add2path的间接变量引用。zsh 也允许间接变量引用,但它的语法完全不同:. 您可能可以创建一个与 交叉兼容的版本,但是如果您没有完全正确地使用它,这往往会导致奇怪的错误;我只是根据 zsh 的需要重写函数。${!1}echodeclare${(P)1}eval

编辑:如果您想在 bash 和 zsh 下使用相同的代码,eval可能比尝试检测您所在的 shell 并使用基于此的条件代码更好。这是编写跨外壳兼容版本的快速尝试:

if ! eval "echo \"\$$1\"" | egrep "(^|:)$2(:|\$)" > /dev/null ; then
    eval "declare -g $1=\"\$$1:\$2\""
    export "$1"
    ...

引用很难看,但只要$1包含有效的标识符,它就可以正常工作;如果不是这样,通常的eval问题可能会引起他们的丑陋。


推荐阅读