问题
因为 zsh和 bash的指令不能完全兼容,因此很多在bash中运行的指令不能在zsh中直接运行。
比较常见的一个问题就是:
我在 ~/.bashrc
中有一些加载 ros2
配置的指令, 如下:
source /opt/ros/humble/setup.bash
source /usr/share/colcon_cd/function/colcon_cd.sh
export _colcon_cd_root=/opt/ros/humble/
source ~/ros2_ws/install/local_setup.bash
在zsh中运行 source ~/.bashrc
会报错,
/usr/share/bash-completion/bash_completion:45: command not found: shopt
/usr/share/bash-completion/bash_completion:1596: parse error near `|'
/opt/ros/humble/setup.bash:.:11: 没有那个文件或目录: /home/username/setup.sh
/usr/bin/python3: can't open file '/home/username/_local_setup_util_sh.py': [Errno 2] No such file or directory
但是,在终端输入 exec bash
进入bash运行此命令就不会有问题。
为解决这个问题,ros提供了 .zsh
文件来代替 .bash
文件,将对应的配置在 .zshrc
中重写可以解决此问题,具体可以参考此博客:安装zsh、oh-my-zsh及zsh安装之后ros配置的一些问题。
但是对于习惯了写 .bashrc
的我而言,不想把大量的命令都迁移到 .zshrc
中,于是寻找了一种新的解决方案。
解决思路
最开始想到的解决方法时我在zsh的shell里运行一个bash的subshell来加载 .bashrc
,但是很遗憾的一件事是在 subshell 中设置的环境变量和所做的更改在 subshell 结束时会丢失,不会影响父 shell。
所以解决方案就只能是切换到bash再切换回zsh。
手动解决:
如果需求不是很大,可以手动执行 exec bash
切换到bash环境中,因为切换到bash后会自动执行 source ~/.bashrc
,所以切换到bash以后再执行exec zsh
切换回来就有了 ~/.bashrc
中的配置。
#在zsh中执行
exec bash
#在bash中执行
exec zsh
自动配置 source ~/.bashrc
我们可以在 ~/.bashrc
中进行逻辑上的自动配置,首先通过编辑器打开~/.bashrc
,在顶部加入如下代码:
if [ -n "$BASH_VERSION" ]; then
echo "USING BASH!"
elif [ -n "$ZSH_VERSION" ]; then
echo "USING ZSH!"
export __USE_ZSH=1
exec bash
fi
其中:echo
表示输出显示,作用是提示用户。
这里的逻辑就是当在zsh环境中运行该文件,会设置一个变量 __USE_ZSH=1
并且执行 exec bash
进入到bash环境中。
其次在底部加入如下代码:
if [[ $__USE_ZSH -eq 1 ]]; then
echo "ENTER ZSH!"
unset __USE_ZSH
exec zsh
fi
这里的逻辑就是如果查询到我们设置的环境变量 __USE_ZSH == 1
,
那么将会删除此环境变量并且切换到zsh环境中。这也就实现了我们需要的功能。
注意:
此时,不可以直接将 source ~/.bashrc
加入到 ~/.zshrc
中,因为如果这样做,将会导致启动zsh时运行 source ~/.bashrc
转入到 bash,而bash最后又会 exec zsh
进入到zsh,形成死循环。