fish 中还有一个比较花哨的地方,可以打开浏览器选择主题和各种配置。直接执行 fish_config
就打开了。
另一个需要配置的一些地方就是我自己常用的两个函数了:
proxy
, 打开关闭命令行代理auto_venv
,自动激活和关闭 Python 虚拟环境
以 proxy 来看一下,fish 的函数还是很直观的。
function proxy if test "$argv[1]" = "on" if test "$argv[2]" = "" echo "No port provided" return 2 end # proxy offered by local shadowsocks export http_proxy="http://127.0.0.1:$argv[2]" export https_proxy="http://127.0.0.1:$argv[2]" else if test "$argv[1]" = "off" set -e http_proxy # set --erase set -e https_proxy else if test "$argv[1]" != "" echo "Usage: proxy - view current proxy proxy on PORT - turn on proxy at localhost:PORT proxy off - turn off proxy" return 1 end echo "Current: http_proxy=$http_proxy https_proxy=$https_proxy" end
后,还可以把 zsh 的 history 迁移到 fish 中来。令人没想到的是,这都有现成的脚本:
pip install zsh-history-to-fish zsh-history-to-fish -n # -n 不要转化 && 和 ||
fish 需要一段时间才会重新读取 history 文件。至此,迁移完毕啦。
后记
在切换到 fish 之后我还是对 zsh 为什么这么慢念念不忘,在对 .zshrc
做了一番 profile 和二分查找之后终于找到了罪魁祸首,和新电脑的硬件并没有什么关系,而是这样一行:
[ -d /home/linuxbrew/.linuxbrew/bin ] && path+=(/home/linuxbrew/.linuxbrew/bin)
这行人畜无害的命令意思是:如果机器上有 linuxbrew 就把它添加到路径里。而在我的 M1 MacBook,不知道为啥 /home
被挂载到了一个网络目录,所以每次打开一个 shell 的时候都会执行一个网络操作,而且这个服务器还可能在美国,能不慢么……删除了这行后,zsh 启动又恢复到正常水平。
┬─[yifei@bogon:~]─[21:45:06] ╰─>$ ll /home lrwxr-xr-x 1 root wheel 25B Dec 4 14:46 /home -> /some/network/volume
不过即便如此,切换到 fish 还是值得的,一则简化并看懂了自己的配置,二则对于 shell 启动时间也是有优化的:
┬─[yifei@bogon:~]─[19:05:15] ╰─>$ time zsh -i -c exit ________________________________________________________ Executed in 254.61 millis fish external usr time 148.16 millis 0.07 millis 148.10 millis sys time 98.99 millis 1.59 millis 97.40 millis ┬─[yifei@bogon:~]─[19:07:44] ╰─>$ time fish -i -c exit ________________________________________________________ Executed in 44.84 millis fish external usr time 16.57 millis 0.08 millis 16.49 millis sys time 21.33 millis 1.67 millis 19.66 millis
可以看到在我的配置下,fish 比 zsh 还是快多了。
最后贴上自己的配置文件供参考:
###### .dotfiles/fishrc ###### # vi:ft=fish set DISABLE_FZF_AUTO_COMPLETION true export TERM="xterm-256color" export EDITOR="vi" # PATH settings set PATH $HOME/.local/bin $HOME/.cargo/bin $HOME/.dotfiles/bin $PATH # Load HomeBrew export HOMEBREW_NO_AUTO_UPDATE=1 export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles test -f /opt/homebrew/bin/brew && eval (/opt/homebrew/bin/brew shellenv) test -f /usr/local/bin/brew && eval (/usr/local/bin/brew shellenv) if uname | grep Linux set PATH /home/linuxbrew/.linuxbrew/bin $PATH end # Aliases alias dc=docker-compose alias pc=podman-compose alias t='tmux -2' alias tmux='tmux -2' alias cd..='cd ..' alias py=python alias ipy='python -m IPython' alias g='git' alias ll='ls -alh' alias :q='exit' alias :wq='exit' alias mkdirp='mkdir -p' alias shn='sudo shutdown -h now' alias mirror='wget -E -H -k -K -p' alias sudo='sudo ' # magic trick to bring aliases to sudo alias px="proxychains4" alias lcurl='curl --noproxy localhost' alias save-last-command='history | tail -n 2 | head -n 1 >> ~/.dotfiles/useful_commands' alias topcpu='ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head' alias topmem='ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head' # Venv auto actiavation function __auto_source_venv --on-variable PWD --description "Activate/Deactivate virtualenv on directory change" status --is-command-substitution; and return # Check if we are inside a git directory if git rev-parse --show-toplevel &>/dev/null set gitdir (realpath (git rev-parse --show-toplevel)) else set gitdir "" end # If venv is not activated or a different venv is activated and venv exist. if test "$VIRTUAL_ENV" != "$gitdir/.venv" -a -e "$gitdir/.venv/bin/activate.fish" source $gitdir/.venv/bin/activate.fish # If venv activated but the current (git) dir has no venv. else if not test -z "$VIRTUAL_ENV" -o -e "$gitdir/.venv" deactivate end end # Proxy switcher function proxy if test "$argv[1]" = "on" if test "$argv[2]" = "" echo "No port provided" return 2 end # proxy offered by local shadowsocks export http_proxy="http://127.0.0.1:$argv[2]" export https_proxy="http://127.0.0.1:$argv[2]" else if test "$argv[1]" = "off" set -e http_proxy set -e https_proxy else if test "$argv[1]" != "" echo "Usage: proxy - view current proxy proxy on PORT - turn on proxy at localhost:PORT proxy off - turn off proxy" return 1 end echo "Current: http_proxy=$http_proxy https_proxy=$https_proxy" end # Load fzf config test -f ~/.dotfiles/fzf.fish && source ~/.dotfiles/fzf.fish ###### .config/fish/config.fish ###### if status is-interactive # Commands to run in interactive sessions can go here end test -f ~/.dotfiles/fishrc && source ~/.dotfiles/fishrc ###### .dotfiles/fzf.fish ###### # vi:syntax=sh export FZF_DEFAULT_COMMAND='fd --type f' export FZF_CTRL_T_COMMAND='fd --type f' export FZF_ALT_C_COMMAND='fd --type d' export FZF_COMPLETION_TRIGGER='' export FZF_DEFAULT_OPTS="--height 40% --reverse --border --prompt '>>> ' \ --bind 'alt-j:preview-down,alt-k:preview-up,alt-v:execute(vi {})+abort,ctrl-y:execute-silent(cat {} | pbcopy)+abort,?:toggle-preview' \ --header 'A-j/k: preview down/up, A-v: open in vim, C-y: copy, ?: toggle preview, C-x: split, C-v: vsplit, C-t: tabopen' \ --preview 'test (du -k {} | cut -f1) -gt 1024 && echo too big || highlight -O ansi -l {} 2> /dev/null || cat {} || tree -C {} 2> /dev/null'" export FZF_CTRL_T_OPTS=$FZF_DEFAULT_OPTS export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window hidden:wrap --bind '?:toggle-preview'" export FZF_ALT_C_OPTS="--height 40% --reverse --border --prompt '>>> ' \ --bind 'alt-j:preview-down,alt-k:preview-up,?:toggle-preview' \ --header 'A-j/k: preview down/up, ?: toggle preview' \ --preview 'tree -C {}'" bind \cr 'commandline --replace -- (history | fzf) || commandline --function repaint'
附:Ubuntu 上安装 fish3
sudo apt-add-repository ppa:fish-shell/release-3 sudo apt update sudo apt install fish