Contents
配置
zsh 的配置文件是 $ZDOTDIR
目录下的 .zshenv
、 .zprofile
、 .zshrc
、
.zlogin
、 .zlogout
这几个文件。如果 ZDOTDIR
没有设置,那么就使用默认
的 HOME
目录。这几个文件的用途都是不言自明的了,其中主要的配置会在用于
非登录 shell 的 .zshrc
里面进行,而 .zshenv
则用于设置搜索路径以及其他
一些重要的变量。需要注意的是, .zshenv
里面不应该包含产生文本输出的命
令,也不应该随意假设执行的时候 shell 已经绑定到了一个 tty 上。
提示符
可以使用 prompt
变量来配置 zsh 的提示符,提示符可以显示的信息非常丰富,详
细可以参考 zsh 的文档,我使用如下设置来让他的提示符更像 bash :
prompt='%1/ %(!.#.$) '
另外,在这里可以找到 Phil 的 zsh 的提示符设置,这是一个很 cool 的提示 符,他还详细讲解了他设置这个提示符的脚本,仔细看还可以学到很多 zsh 相 关的知识。
与 TRAMP 配合使用
在 Emacs 里面通过 TRAMP 登录到 zsh 的机器上的时候会挂起,因为无法正确 地识别出命令行提示符。
一种解决办法
zsh 有额外的默认打开的功能,让 TRAMP 不能正确处理。额外的功能由
prompt_cr
和 prompt_sp
两个变量控制。 prompt_cr
打开的话,在输出提示符
之前会输出回车符,这是多行编辑所需要的,但是这样有时候如果上一个命令的
输出最后一行没有换行的话就会被“吃掉”,例如:
$ setopt prompt_cr $ setopt No_prompt_sp $ echo -n "foobar" $
看到 "foobar"
已经被吃掉了,但是如果同时打开了 prompt_sp
变量,则会在
未换行的那一行末尾打印一个反色粗体的 %
(或者是 #
)并打印适量的空格让提
示符延伸到下一行。这个功能本来是不错的,但是在 Emacs 里面用 M-x shell
得到的 shell 里面不好用,而且多余的 %
(或者 #
) 会影响 TRAMP 识别提示
符,造成 TRAMP 不能正常工作。要解决这个问题的办法也是比较简单的,因为
Emacs 和 TRAMP 使用的 TERM
变量都是 dumb
,只要在 TERM
是 dumb
的时候
关掉这两个选项就好了,在 ~/.zshrc
里面加入:
可是这样仍然无法使用 TRAMP 的 sudo 方式来访问本地文件,也不知道是怎么
一回事情,这个是很郁闷的。这个问题暂时还没有解决,只有先用 bash 作为登
录 shell ,然后查看 TERM
变量,如果是 linux
或者 screen
的话就运行 zsh
,因为 linux
是在虚拟终端里面的 TERM
值,而 screen
是我在 X 下运行
urxvt 里面 Screen 里的 TERM
值,其他情况下通常都不需要 zsh 。
另外,在 Emacs 里面用 M-x shell
得到的终端会设置 EMACS
变量 ,在这里面
可以把 zle (Z-Shell Line Editor) 禁用掉。
在 ~/.bashrc
里面写
在 ~/.zshrc
里面写
更好的解决办法
后来我在 Emacs 的邮件列表里面问了,原来 zsh 同时使用左右两个提示符,所
以会造成问题,现在登录 shell 仍然使用 zsh ,只需要在 ~/.zshrc
里面加入
就可以了。
单词分界
zsh 的命令行编辑器默认用起来不是很方便,特别是在编辑路径的时候,比如输
入 /tmp/foo/bar
,再用 Alt+Backspace
来删除一个词的时候会把整个路径全
部都删除掉,这是因为 /
被当作单词的一部分的原因,而通常我们更习惯的是
每次删除一个目录名。这可以通过修改 WORDCHARS
变量来实现,这个变量是一
个表示除了字母和数字之外还有哪些符号是一个单词可以包含的,默认值是
?*_-.[]~=/&;!#$%^(){}<>
可以看到里面包含了 /
,只要定制为自己需要的值就行了,例如,从中去掉 /
和 .
要显得更习惯一点。
WORDCHARS='*?_-[]~=&;!#$%^(){}<>'
键绑定
zsh 可以使用 bindkey
命令来进行键绑定,快捷键的语法里面一些常用的特殊
字符的表示方法是:
\e 或 \E |
Escape |
\M[-]X |
就类似于 Emacs 的 M-X |
\C[-]X 或 ^X |
类似于 Emacs 的 C-X |
例如,zsh 的命令行编辑器也实现了 Emacs 的 kill-ring 的功能,我习惯于把
set-mark-command
绑定到 M-<SPACE>
上面,在 zsh 里面为了迎合这个习惯,
我可以这样写(我一直使用 Alt
作为 Meta
键):
bindkey '\e ' set-mark-command
这样就很舒服了,可惜 zsh 里面不能像 Emacs 那样高亮显示当前的 region ,
不过仍然有 Emacs 的那个 C-x C-x
交换 mark 和 pointer 的功能,因此查看
当前 region 还是很方便的。
交互使用
通配符
除了支持经典的通配符之外,如果设置了 EXTENDEDGLOB
,那么 zsh 还支持一
些扩展的通配符:
否定匹配
^
可以用于取接下来的模式的否定,例如:
% ls -d ^*.c Makefile file.pro link morestuff run2 run303 bar.o foo main.h pipe run234 stuff file.h foo.o main.o run123 run240 sub % ls -d ^*.* Makefile link pipe run2 run240 stuff foo morestuff run123 run234 run303 sub
整数范围匹配
<x-y>
可以匹配在 x
到 y
范围内的整数:
% ls run<200-300> run234 run240 % ls run<-200> run 123 run2 % ls run<-> run123 run2 run234 run240 run303
分组功能
% ls (foo|bar).* bar.o foo.c foo.o % ls *.(c|o|pro) bar.o file.pro foo.c foo.o main.o q.c
递归匹配
**/
用于打开递归匹配。
% ls -d **/f*bar footbar stuff/fbar stuff/fbar/foobar stuff/xxx/foobar % ls -d stuff/**/f*bar stuff/fbar stuff/fbar/foobar stuff/xxx/foobar % ls -d fo*bar footbar % ls -d **/fo*bar footbar stuff/fbar/foobar stuff/xxx/foobar
去除特例
使用 ~
可以从模式中去除不想要的匹配。
% ls *.c foo.c foob.c bar.c % ls *.c~bar.c foo.c foob.c % ls *.c~f* bar.c
类型限定
在模式后面可以使用圆括号加上限定符限定匹配的类型,限定符包括:
/
目录@
符号链接x
所有者具有可执行权限X
其他人具有可执行权限r/R
所有者/其他人可读w/W
所有者/其他人可写.
普通文件p
命名管道U
属于你的文件s
setuid 文件u3338
属于 uid 为 3338 的用户的文件
他们可以组合使用,还可以哟个 ^
来表示否定,例如 *(W^@)
、 *(x^@/)
等。
命令替换
如同 bash 一样,zsh 也支持 ``
和 $()
这样的命令替换用于使用程序的输出
作为命令行。对应于 bash 那方便的 <()
命令,也可以在 zsh 中使用:
grep foo <(ls -l)
就是把 ls -l
的输出作为一个命名管道,再把这个管道的名字(事实上,是指向
这个管道的一个符号链接的名字)作为参数传递给 grep
程序,不过,这样也有
一些不足的地方,例如下面的命令就不能成功:
mail -f <(zcat ~/mail/oldzshmail.Z)
因为 mail
不能把一个管道打开作为邮件箱。不过,zsh 还提供了另外一个类似
的命令 =()
,它不是创建管道,而是创建一个临时文件,并在程
序运行结束之后删掉临时文件。
别名
zsh 有和其他 shell 一样的别名,除此之外,zsh 还有一种“global alias”, 它可以出现在命令行的任何地方,通常用于为一些常用的比较长的名字、地址等:
alias -g gg='http://www.google.com' w3m gg
不过这个功能不能被滥用了,否则会造成一片混乱的局势。
历史
zsh 可以使用 csh 那样的历史替换功能。另外,还有一个内置的 fc 命令可以
对历史里面的命令行进行编辑之后再执行,默认的编辑器是 vi ,不过可以通过
变量 FCEDIT
来更改。另外,给 fc 传递 -e
选项可以指定 ename
参数用于覆
盖 FCEDIT
的值,如果 ename
是 -
的话,则不调用编辑器编辑,这个功能是很
常用的,所以还有一个内置命令 r
,就等价于 fc -e -
。
$ echo foobar foobar $ echo hello world hello world $ r world=zshell echo hello zshell hello zshell $ fc -l 1 echo foobar 2 echo hello world 3 r world=zshell 4 echo hello zshell $ r bar=baz 1 echo foobaz foobaz
重定向
zsh 支持一种扩展的重定向语法,由 multios
选项控制(默认是打开的)。这样
可以避免使用 tee 程序,例如,在通常的是 shell 里面需要这样来完成重定向
到多处的任务:
echo foo | tee file1 > file2
现在在 zsh 里面只需要这样
echo foo > file1 > file2
另外,对于输入重定向也有这个功能,例如
prog < file1 < file2
等价于
cat file1 file2 | prog
另外,管道也相当于一个重定向,并且管道的输入先于输入重定向,从下面这个 测试可以看出来:
echo then this > testfile echo this first | cat < testfile
命令行编辑
zsh 有一个强大的命令行编辑器,可以模拟 Emacs 或者 vi 的快捷键方式,还 支持多行编辑。
另外,还有一些非常人性化的功能,比如,你正输入了一个命令,突然忘记了要
用哪些文件名作为参数,这个时候你不想直接退出,因为这样你下一次就要再把
这个命令整个输入一遍,虽然是不完整的命令,这个时候可以使用 ESC-Q
,把当
前输入的不完整的命令放入 buffer stack 中,在下一次命令提示符显示出来的
时候这个不完整的命令将会被显示出来,处于待编辑状态。
更特殊的情况是你忘记了命令的参数,需要 man 一下,这个时候直接使用=ESC-H=
即可把当前命令放入 buffer stack 再运行 run-help prog
命令( run-help
是
man
的一个别名)。
还有一个有趣的命令是 ESC-A
,他直接执行当前命令,并将其放入 buffer
stack 中,这对于执行一系列的类似的命令非常有用。
另外, ESC-'
命令用于创建当前命令行的引用,有时候是非常方便的,例如,
你要输出一句
don't do that; type 'rm -rf \*', with a \ before the *.
只需要直接输入这一句话,然后按下 ESC-'
,就会自动转换成
'don'\"t do that; type '\"rm -rf \*'\", with a \ before the *.'
再跳到行首,输入 echo
就可以了。
脚本编程
使用 Emacs 编辑 zsh 脚本
Emacs 已经支持 zsh 脚本的编辑,会自动识别 #!/bin/zsh
并进入
shell-script-mode 。在 shell-script-mode 里面可以使用 C-c : zsh
来得到
针对 zsh 的编辑功能支持。