哦!我的Zsh!
2014-03-27
不久前,我从Bash切换到了Zsh,写点东西供读者以及我自己参考。
Zsh是什么
Zsh是一个Unix Shell,它在兼容标准的POSIX Shell(以及可仿真Bash)的同时,提供了极强的可定制性和可扩展性,以及一些有趣的功能,比如:
- 自定义提示符,可以与git等软件集成;
- 可编程的命令补全,例如输入kill命令后按tab会自动列出进程;
- 全局可共享、并且能以各种方式管理的命令历史;
- 命令补全错误纠正、界面主题包、不输入cd只输入目录名直接进入目录……
Zsh在使用时需要注意的独特之处包括:
- 通配符展开是语言级的,通配符无法匹配是一个语法错误;
- 一些命令是内建的,与其它Shell中的不同,例如echo命令在默认情况下会进行字符转义;
- 从1开始数(第三声)数(第四声)。
顺带一提:Zsh取自Zhong Shao的登录名——此人是作者Paul Falstad的大学助教。
为了名垂青史,请使用姓名拼音作为登录名,并耐心等待躺枪。我常常混淆Zsh和ZFS的各种梗,后者的“Z”代表Zettabyte和“终极”(作为最后一个字母)。
Oh-my-zsh
为了充分体验Zsh的强大之处,我们需要对它进行一些配置。
一个简单的方法是使用Oh-my-zsh——Oh-my-zsh是一个Zsh配置管理框架,自带上百个插件和主题。
直接下载并作为Shell脚本运行http://install.ohmyz.sh
即可安装。
当然,你也可以选择从零开始进行配置。
配置
Zsh的配置文件位于~/.zshrc
。
从文件末尾开始添加配置。首先,我们可以根据自己的喜好,添加一些别名:
1 alias ll='ls -al'
2 alias la='ls -a'
3 alias apt-get='sudo apt-get'
4 alias gita='git add'
5 alias gitc='git commit'
6 ...
扩展名别名:
1 alias -s gz='tar -xzvf'
2 alias -s bz2='tar -xjvf'
3 alias -s out='valgrind'
4 ...
还可以加上快捷地址,比如hash -d www='/var/www/'
。
Zsh的提示符是可以修改的。我使用的版本:
1 ZSH_THEME_GIT_PROMPT_CLEAN=""
2 ZSH_THEME_GIT_PROMPT_DIRTY=" !"
3 ZSH_THEME_GIT_PROMPT_PREFIX=" :"
4 ZSH_THEME_GIT_PROMPT_SUFFIX=""
5 PROMPT=$(echo "${ret_status}%{$fg_bold[green]%}%p%{$fg[blue]%}%5~\
6 %{$fg_bold[cyan]%}$(git_prompt_info) %{$reset_color%}")
一些关于补全和错误纠正的配置:
1 zstyle ':completion:*' completer _complete _match _approximate
2 zstyle ':completion:*:match:*' original only
3 zstyle ':completion:*:approximate:*' max-errors 1 numeric
4
5 zstyle ':completion:*:*:kill:*' menu yes select
6 zstyle ':completion:*:kill:*' force-list always
7
8 zstyle ':completion:*:cd:*' ignore-parents parent pwd
扩展
以下是一些从网上收集的小程序,可以直接在.zshrc
中使用。
对每个目录使用独立的命令历史:
1 mkdir -p $HOME/.zsh_history$PWD
2 export HISTFILE="$HOME/.zsh_history$PWD/zhistory"
3
4 cd() {
5 builtin cd "$@"
6 fc -W
7 local HISTDIR="$HOME/.zsh_history$PWD"
8 if [ ! -d "$HISTDIR" ] ; then
9 mkdir -p "$HISTDIR"
10 fi
11 export HISTFILE="$HISTDIR/zhistory"
12 touch $HISTFILE
13 local ohistsize=$HISTSIZE
14 HISTSIZE=0
15 HISTSIZE=$ohistsize
16 fc -R
17 }
18
19 function allhistory {
20 cat $(find $HOME/.zsh_history -name zhistory)
21 }
22
23 function convhistory {
24 sort $1 | uniq |
25 sed 's/^:\([ 0-9]*\):[0-9]*;\(.*\)/\1::::::\2/' |
26 awk -F"::::::" '{ $1=strftime("%Y-%m-%d %T",$1) "|"; print }'
27 }
28
29 function histall {
30 convhistory =(allhistory) | sed '/^.\{20\} *cd/i\\'
31 }
32
33 function hist {
34 convhistory $HISTFILE
35 }
36
37 function top50 {
38 allhistory | awk -F':[ 0-9]*:[0-9]*;' '{ $1="" ; print }'\
39 | sed 's/ /\n/g' | sed '/^$/d' | sort | uniq -c | sort -nr | head -n 50
40 }
语法高亮:
1 setopt extended_glob
2 TOKENS_FOLLOWED_BY_COMMANDS=\
3 ('|' '||' ';' '&' '&&' 'sudo' 'do' 'time' 'strace' 'man')
4
5 recolor-cmd() {
6 region_highlight=()
7 colorize=true
8 start_pos=0
9 for arg in ${(z)BUFFER}; do
10 ((start_pos+=${#BUFFER[$start_pos+1,-1]}\
11 -${#${BUFFER[$start_pos+1,-1]## #}}))
12 ((end_pos=$start_pos+${#arg}))
13 if $colorize; then
14 colorize=false
15 res=$(LC_ALL=C builtin type $arg 2>/dev/null)
16 case $res in
17 *'reserved word'*) style="fg=magenta,bold";;
18 *'alias for'*) style="fg=cyan,bold";;
19 *'shell builtin'*) style="fg=yellow,bold";;
20 *'shell function'*) style='fg=green,bold';;
21 *"$arg is"*)
22 [[ $arg = 'sudo' ]] && style="fg=red,bold"\
23 || style="fg=blue,bold";;
24 *) style='none,bold';;
25 esac
26 region_highlight+=("$start_pos $end_pos $style")
27 fi
28 [[ ${${TOKENS_FOLLOWED_BY_COMMANDS[(r)${arg//|/\|}]}:+yes} = 'yes' ]]\
29 && colorize=true
30 start_pos=$end_pos
31 done
32 }
33
34 check-cmd-self-insert() { zle .self-insert && recolor-cmd }
35 check-cmd-backward-delete-char() { zle .backward-delete-char && recolor-cmd }
36
37 zle -N self-insert check-cmd-self-insert
38 zle -N backward-delete-char check-cmd-backward-delete-char
按两次esc键,快捷sudo:
1 sudo-command-line() {
2 [[ -z $BUFFER ]] && zle up-history
3 [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
4 zle end-of-line
5 }
6 zle -N sudo-command-line
7 bindkey "\e\e" sudo-command-line
当然,Zsh还可以变得更酷、更强。通过扩展和配置,我们可以让它做各种事情,尽管发挥你的想象力吧!