zsh
TODO
命令行编辑
bindkey命令用于设置键绑定。
控制字符
M-数字
- 重复后续命令 N 次,重复则表示多位数
M-q
- 暂时离开当前命令的编辑,执行其它命令。
^Q
也绑定到这里,但没有作用 M-. M-_
- 循环 yank 最近命令的最后一项
^Xu ^X^U ^_
undo- 撤消
^V
quoted-insert- 按本义插入字符
^X^K
kill-buffer- 删除整个命令
^Xs
history-incremental-search-forward- 向后搜索历史。默认
^S
也绑定到这里,但没有作用 ^X^F
自定义^]
vi-find-next-char- 向后搜索字符
(未绑定)
自定义M-]
vi-find-prev-char- 向前搜索字符
M-^_
copy-prev-word- 复制前一个单词
^X^B
vi-match-bracket- 跳到对应的括号
M-'
quote-line- 用单引号括起整行
M-?
which-command- 查询当前命令的位置
^X^O
overwrite-mode- 插入/替换
M-x
execute-named-cmd- 按命令名执行一条编辑命令
M-z
execute-last-named-cmd- 执行上一条编辑命令
(未绑定)
where-is- 查询命令被绑定到什么键上去了
历史记录
M-<
beginning-of-buffer-or-history- 取出历史记录的第一条命令
M->
end-of-buffer-or-history- 取出历史记录的最后一条命令
^o
accept-line-and-down-history- 执行本行命令并取出历史记录中的下一项
补全和扩展
这些内容在手册的 Completion System -> Bindable Commands 下。
^Xa
_expand_alias- 作为别名扩展
M-/
_history-complete-older- 从历史记录的单词中寻找补全
(未绑定)
自定义M-/
_history-complete-older- 从历史记录的单词中寻找旧的补全
^Xg
list-expand- 列表扩展结果,但不进行实际的扩展。在文件名生成时,总是按文件名排序。
=cmd
可扩展成命令 cmd
的绝对路径(即 which cmd
)。
其它
^a
- 使用上行命令,删除第一个 a
^a^b
- 使用上行命令,其中的第一个 a 被 b 取代
^X^V
vi-cmd-mode- 原地切换到vi命令模式,按
i
键后回到Emacs模式
设置
使用 $EDITOR
编辑命令行
autoload edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line
bash式 backward-kill-word
:
autoload -U select-word-style
select-word-style bash
来源:stackoverflow: zsh: stop backward-kill-word on directory delimiter
URL 中的特殊字符自动转义:
autoload -U url-quote-magic
zle -N self-insert url-quote-magic
提示符
函数 precmd
在显示提示符之前执行,可以在此时修改提示符或者打印消息。
内建命令
alias
后缀别名,在命令行上指定一个文件,当其后缀符合时使用该命令打开。文件不可使用引号括起。
alias -s jar="java -jar"
设置全局别名,该别名在命令行中任意位置单独作为一个单词时将被替换。
alias -g NUL="/dev/null"
bindkey
显示所有绑定:
bindkey -L
绑定到一个功能:
bindkey "^U" backward-kill-line
绑定到一个键序列:
bindkey -s "^J" "^[[A^[[B"
vared
交互式编辑变量的值。
vared VAR
特殊函数
command_not_found_handler
- 命令未找到时执行
zshexit
- 退出时执行
命令行选项
-x
- 启动时打印执行的命令
文件
作为 login shell 时会读取 ~/.zprofile
。
选项
setopt
置位一个选项, unsetopt
复位一个选项。不加参数的 setopt
显示所有已置位的选项,不加参数 unsetopt
显示所有已复位的选项。选项名不区分大小写。
# append command to history file once executed
setopt inc_append_history
extended_glob
- 启用
(#qx)
式 glob sh_word_split
- 像bash那样扩展变量后进行分割(否则使用单引号括起来)。也可以使用 ${=name} 的形式分割一个变量
扩展
扩展即Expansion。
冒号修饰符
冒号用来修饰变量,主要用于文件名。对于变量,使用 $a:r
形式,对于字面字符串,可使用 .(:a)
形式的路径扩展
- a
- 绝对路径
- A
- 绝对路径,解析符号链接
- c
- 命令名->完整路径
- e
- 扩展名
- h
- 去掉最后一项,类似 dirname
- l
- 小写
- p
- 打印,但不执行。用于历史扩展
- q
- 用引号括起,并进行适当的转义
- Q
- 去掉一层引号
- r
- 去掉扩展名
- s/l/r[/]
- 替换一次出现。使用
gs
或者后加:G
修饰来替换所有出现 - &
- 重复上一次替换
- t
- 类似于 basename
- u
- 大写
- x
- 按空格分隔后再加引号(如同
q
那样)
补全
mpg123 <tab> , 候选菜单中只出现扩展名为 .mp3 .MP3 的文件:
zstyle ':completion:*:*:mpg123:*' file-patterns \
'*.(mp3|MP3):mp3\ files *(-/):directories'
zstyle ':completion:*:*:ogg123:*' file-patterns \
'*.(ogg|OGG):ogg\ files *(-/):directories'
历史记录
zsh的历史记录文件打开为乱码,这是因为在 input.c
中的 shingetline()
函数中处理过。得到正确的文本的 C 程序如下:
//=====================================================================
// 让 zsh 的历史记录可读
//=====================================================================
#include<unistd.h>
//---------------------------------------------------------------------
void readhist(){
unsigned char c, d;
int change = 0;
while(read(0, &c, 1)){
if(c != 0x83){
if(change){
d = c ^ 32;
}else
d = c;
write(1, &d, 1);
change = 0;
}else
change = 1;
}
}
//=====================================================================
将文本还原的程序如下:
static int ismeta(unsigned char ch){
return (ch > 0x83 && ch < 0x9e)
|| ch == 0xa0 || ch == 0x83 || ch == 0;
}
void writehist(){
unsigned char c, d;
while(read(0, &c, 1)){
if(ismeta(c)){
d = 0x83;
write(1, &d, 1);
d = c ^ 32;
write(1, &d, 1);
}else
write(1, &c, 1);
}
}
模块
zpty
zmodload zsh/zpty
zpty test ls ~ # test 是名字
zpty -r test > a # 读取输入到文件 a
zpty -d test # 删除名字为 test 的(省略名字则删除全部)
zpty # 列出全部(已完成和未完成的)
奇怪的是, zpty -r
的结果不能直接传给 less
。
应用示例
ptyless () { # 使用伪终端代替管道,对 ls 这种“顽固分子”有效 {{{2
zmodload zsh/zpty
zpty ptyless ${1+"$@"}
zpty -r ptyless > /tmp/ptyless.$$
less /tmp/ptyless.$$
rm -f /tmp/ptyless.$$
zpty -d ptyless
}
其它功能
sticky-note
简易的在命令行上的笔记记录,使用zsh命令行历史相同的格式存储于文件 $STICKYFILE
,默认为 ~/.zsticky
。
启用
autoload sticky-note
连续两次回车退出。要查看之前的笔记,只需使用 ^P
等查阅历史记录。
清理
重定向
pipe stderr
,保留 stdout
[1]:
3>&1 1>&2 2>&3
multios
打开 multios 选项时,重定向的顺序有关系。如以下命令
cat file >&1 > output
会将文件输出到标准输出的同时,输出到文件 output
。但顺序反过来则不行。
在标准输出上显示标准错误,同时将两者都记录到文件中
cmd 2>&1 &> log
扩展
历史记录扩展
指定历史记录
- 上条记录:
!!
或者!
。 - 本条记录:
!#
。 - 使用整数来按序号指定。使用负值来倒序指定(
!-1
等同于!!
。 - 按开头向上查找:
!str
修饰符
指定某个参数,使用数字或者 ^
、 $
。也可以使用范围:
x-y
*
表示所有参数(除去命令)x*
(等同于x-$
)-
除去最后一个参数(包括命令)x-
(与x*
类似,但是不含最后一个参数)
对指定历史记录进行替换:
# 只替换一次
!!:s/regex/replacement
# 多处替换
!!:gs/regex/replacement
!!:s/regex/replacement/:G
其中的 /
分隔符也可以使用其它字符。
替换也可以用 ^a^b
的形式。多处替换时使用 ^a^b^:G
。
只打印处理后的历史记录,不执行:[2]
!!:p:gs/what/ever
!!:gs/what/ever/:p
进程替换
使用 <(command)
和 >(command)
的形式,在系统支持时会使用 /dev/fd
,否则使用命名管道。使用 =(command)
形式将使用临时文件,以支持 lseek
。
花括号扩展
选项 BRACE_CCL
如果设置,将扩展形如 {a-f} 和 {3-9} 这样的字符类。[3]
字符串替换
${name/pattern/repl}
${name//pattern/repl}
pattern
中需要转义的特殊字符:
#
- 字符串开头
%
- 字符串结尾
例如,清理 Vim 撒消文件:
cd $VIM_UNDO_DIR
for f in *; do [[ ! -f ${f//\%//} ]] && rm -v $f; done
文件名生成
筛选
按类型:
- / 目录
- F 非空目录(Full)
- . 普通文件(不论执行权限)
- @ 软链接
- = 套接字
- p 命名管道
- * 可执行的普通文件
- % 设备文件
- %b 块设备文件
- %c 字符设备文件
按权限:
- r 所有者可读
- w 所有者可写
- x 所有者可执行
- A 组可读
- I 组可写
- E 组可执行
- R 其它人可读
- W 其它人可写
- X 其它人可执行
- s set-user-id
- S set-group-id
- t sticky
- fspec 指定权限
按当前环境:
- U 当前有效用户拥有
- G 组为当前用户的有效组
例子:
- 断掉的软链接
(-@)
- 空目录
(/^F)
排序
使用 oc
来指定排序方式,如: *.log(oL)
。在小括号中使用带方括号的数字来选择指定项,如 *(om[1])
是最近修改过的文件。
c
可以是:
- n: 文件名
- L: 文件大小(length)
- l: 链接数
- a, m, c: 文件的访问时间、内容修改时间、i 节点修改时间。最近的文件最先。
- d: 目录优先。与其它排序选项同时指定时最佳,如
odon
。 - N: 不排序
使用 Oc
来降序排序。也可以使用 ^
(取反)结合 oc
达成。
选项
SH_WORD_SPLIT
- 像bash那样,在扩展未用引用括起的变量时按空白分隔成多个字。默认不设置。
变量
数组
#数组长度
echo ${#commands}
提供默认值
如果 ZDOTDIR
被设置且不为空则使用之,否则使用减号后的值(这里是 HOME
的值):
_zdir=${ZDOTDIR:-$HOME}
设置变量默认值的同时替换
如果 OPTS
被设置且不为空则使用之,否则将其设置为 -v
并使用之:
: ${OPTS:=-v}
代码片断
检查命令是否存在
[[ -n $commands[ilua] ]]
所有非必须的内建命令(有相应的可执行文件的)
% for i in ${(k)builtins}; do [[ -n $commands[$i] ]] && echo $i || true; done | sort | xargs
[ echo false kill printf pwd test true which
问题处理
Home 等键不正常
Arch下默认没有处理这些键。可复制Ubuntu下的 /etc/zsh/zshrc
文件。
问题
select
语句中,中文不能正常显示
评论
People sometimes say Perl has a difficult syntax to understand; I hope I'm convincing you how naive that view is when you have zsh.
参见
外部链接
- zsh中让敲出来的命令带颜色
- A zsh prompt for Git users | SebastianCelis.com,一个能显示 git 仓库状态的提示符配置
- ZSH-LOVERS(1)
- Zsh Workshop: Table of Contents
- Why Zsh is Cooler than Your Shell
- 自定义 zsh 自动补全功能初探 - BheHonTyu's Blogging
- 跟我一起写shell补全脚本(Zsh篇) - SegmentFault
- zsh-completions/zsh-completions-howto.org at master · zsh-users/zsh-completions
- Zsh Native Scripting Handbook
- Better Zsh history - jdhao's blog
- s/bash/zsh/g: 对 bash 中的奇怪行为的吐槽,以及与 zsh 的对比
插件
- Incremental completion on zsh
- zsh-syntax-highlighting, Fish shell like syntax highlighting for Zsh.
- mouse.zsh, 在终端下使用鼠标定位、复制和粘贴
- extract.plugin.zsh, 通用解压脚本
- safe-paste.plugin.zsh, 在粘贴后、执行前先预览/编辑[4]
- scfrazer/zsh-jump-target: jump to a position in a command line
- Vifon/deer: ranger-like file navigation for zsh
补全插件
- zsh-users/zsh-completions
- vhbit/fabric-zsh-autocomplete, for fabric, included in zsh-completions
- Valodim/zsh-curl-completion, for curl
补丁
- [PATCH] Zsh/zpython module, git source: zsh 的 Python 模块
参考资料
- ↑ unix - How to pipe stderr without piping stdout - Server Fault、Re: pipe on stderr
- ↑ 另外,
histverify
选项可以使用回车时只扩展而不执行命令。 - ↑ (zsh brace expansion | seq) for character lists - how? - Stack Overflow
- ↑ 参见 Mort | 危险的Shell,邪恶的HTML已失效,存档