用 zsh 有七八年了,开始用的是 oh my zsh,后来从 skywind3k 大佬的配置文件里抄来了 antigen,用起来还算不错。不过,也有一个问题困扰了好久,antigen 每加载一个插件,就会往 PATH
中塞一个路径,导致路径一大坨,需要改动的时候很难分辨。如下所示:
# 可以左右滑动看看有多长 -> % echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/lib:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/tmux:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/ansible:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/git:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/pip:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/colored-man-pages:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/django:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/docker:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/fzf:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/history:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/kubectl:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/colorize:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/github:/home/ubuntu/.antigen/bundles/robbyrussell/oh-my-zsh/plugins/python:/home/ubuntu/.antigen/bundles/zsh-users/zsh-completions:/home/ubuntu/.antigen/bundles/zsh-users/zsh-autosuggestions:/home/ubuntu/.antigen/bundles/Vifon/deer:/home/ubuntu/.antigen/bundles/nojhan/liquidprompt:/home/ubuntu/.antigen/bundles/willghatch/zsh-cdr:/home/ubuntu/.antigen/bundles/zsh-users/zaw:/home/ubuntu/.antigen/bundles/zsh-users/zaw/functions:/home/ubuntu/.antigen/bundles/wfxr/forgit:/home/ubuntu/.antigen/bundles/zsh-users/zsh-syntax-highlighting:/home/ubuntu/.fzf/bin:/home/ubuntu/.local/bin:/home/ubuntu/.dotfiles/bin:/home/ubuntu/repos/lib/go:/home/ubuntu/repos/unity/go/bin
不知道是不是因为换了 M1 芯片的 Mac 有什么不兼容的地方(并不是),最近 zsh 的加载速度从 1s 涨到了 4s,以前的速度还勉强可以忍,现在想敲个命令都得等 shell 加载半天,实在受不了了。一开始是打算精简下自己的 zshrc 文件,后来看了看发现完全看不懂这个文件,瞎改一通高亮补全都不见了,要啥啥没有,于是索性换个 shell 了。
第一次用 fish 还是刚去头条实习的时候。记得当时看到 fish 眼前一亮,但是因为 bash 用得都不熟练,而 fish 又和 bash 不兼容就暂时放弃了。当时的 fish 为了特立独行,有些 bash 中受欢迎的地方也删掉了,比如说 &&
和 ||
条件执行两个命令,直到最近才补上。没想到和 fish 一别就是六年,今天再次 brew install fish
还真有些一见如故的感觉。
安装好之后还要 sudo echo $(which fish) >> /etc/shells
(zsh),然后就可以 chsh $(which fish)
(zsh),把 fish 扶到正宫位置了~
虽然 chsh 把 bash/zsh 打入冷宫了,但并不是彻底把她们卸载了。当你需要执行一些 bash 脚本的时候,直接 bash my_script.sh
就好了。
开箱即用的补全和高亮
这是原来的 zsh,自动补全和高亮一应俱全,就是启动慢了点。
这是新安装的 fish,自动补全和高亮开箱即用,没有装任何插件,只是切换了一个原生主题,启动飞快。
更妙的两点是,fish 的自动补全是基于上下文的,在不同的位置会有不同的补全;而且 fish 还会自动解析 man page,智能补全命令。
更简单易记的语法
前面提到 fish 和 bash 是不兼容的,更准确得说,fish 不是一个 posix compatible 的 shell,虽然有些和以前的习惯用法不一样的地方,但是这也意味着 fish 可以摆脱一些历史上的设计错误,从而拨乱反正。
比如说,fish 中不使用 $(cmd)
或者 `cmd`
来执行命令替换,直接使用 (cmd)
。
fish 中的 for 循环也更像现代编程语言 (Ruby):
for i in *.pdf echo $i end
而在 bash/zsh 中需要:
for i in *.pdf; do echo $i; done
至少对我而言,for 后面的那个分号是特别容易忘记的。
fish 中不需要 heredoc,因为字符串直接是可以跨行的。当然也可以在每行结尾处加上 \
转义换行。
echo "some string some more string"
相当于 bash 中的:
cat <<EOF some string some more string EOF
如果你装的新版本的 fish,那么是支持浮点数的,以前在命令行做个简单运算还得打开 python,现在直接:
math 2/5 # 0.4
就可以了。不过老版本的 fish 貌似并不支持浮点数,至少 fish 2.7 是这样的。
bash 中最混乱的部分要数字符串了,比如说 ${foo%bar}
(从后向前删除), ${foo#bar}
(从前向后删除), 还有 ${foo/bar/baz}
(正则替换),这个 %
和 #
我从来都不知道是干吗的。在 fish 中全部都替换成了内置命令 string 的方法,和其他语言比较接近,不再是加密代码了。
# 替换字符串 ${var/pattern/replacement} bash -c 'export name=Apple; echo ${name/pp/qq}' name=Apple string replace pp qq $name # ${foo#bar} bash -c 'export name=Apple; echo ${name#App}' name=Apple string replace App '' $name # ${foo%bar} bash -c 'export name=Apple; echo ${name%le}' name=Apple string replace --regex 'le$' '' $name
还有,bash 中的特殊变量也挺难记的,fish 中也都改成了单词:
$*, $@, $1 ...: $argv # 函数或者脚本的参数 $0: status filename # 函数或者脚本的名字 $#: 使用 $argv 的长度 $?: $status # 上一个命令的返回值 $$: $fish_pid # shell 的 pid $!: $last_pid # 上一个命令的 pid $-: 大多数使用是 status is-interactive 和 status is-login