Zsh使用技巧
Zsh 是功能最丰富的交互式 Shell 之一,开箱即用的补全、通配符和历史机制远超 Bash。本文整理日常高频使用的 Zsh 技巧,帮助提升命令行效率。
1. Tab 补全增强
Zsh 的补全系统(completion system)是其最强大的特性之一,通过少量配置即可大幅提升体验。
1.1 大小写不敏感补全
默认情况下补全是大小写敏感的,输入 pdf 无法补全 PDF 文件。在 ~/.zshrc 中添加:
bash
# 大小写不敏感补全
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'
原理:matcher-list 定义了补全匹配规则,m:{a-zA-Z}={A-Za-z} 表示将小写字母映射到大写、大写映射到小写进行匹配。
1.2 菜单选择模式
默认补全是循环切换候选项,开启菜单选择后可以用方向键在列表中挑选:
bash
# 开启菜单选择补全,支持方向键导航
zstyle ':completion:*' menu select
按 Tab 触发补全后,候选项以列表展示,用方向键或 Tab/Shift+Tab 上下移动选择。
1.3 Fuzzy 匹配补全
允许输入部分字符就能匹配,比如输入 fbr 补全到 foobar:
bash
# fuzzy 匹配:允许跳过中间字符
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
- 第二条规则
r:|[._-]=*允许在._-处进行部分匹配 - 第三条规则
l:|=* r:|=*允许在任意位置进行前缀匹配
1.4 补全缓存与颜色
bash
# 启用补全缓存,加速补全响应(如 ssh 主机名补全)
zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path ~/.zcompcache
# 补全列表带颜色
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
2. 历史搜索与快捷键
Zsh 的历史机制支持增量搜索、历史扩展等多种方式快速复用命令。
2.1 基于上下箭头的前缀搜索
默认行为是按时间遍历历史。开启前缀匹配后,输入 git 再按上箭头,只会看到以 git 开头的历史命令:
bash
# 在 ~/.zshrc 中绑定上下箭头为前缀历史搜索
autoload -U up-line-or-beginning-search
autoload -U down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search
bindkey '^[[A' up-line-or-beginning-search # 上箭头
bindkey '^[[B' down-line-or-beginning-search # 下箭头
2.2 Ctrl+R 增量搜索
Ctrl+R 是最常用的历史搜索方式,输入关键词即可实时过滤匹配的历史命令。多次按 Ctrl+R 可以在多个匹配结果间跳转。
Zsh 原生支持此功能,配合 fzf(见第 7 章)可以获得更强大的模糊搜索体验。
2.3 历史扩展操作符
| 语法 | 含义 | 示例 |
|---|---|---|
!! |
上一条完整命令 | sudo !! — 用 sudo 重跑上一条 |
!$ |
上一条命令的最后一个参数 | mkdir foo && cd !$ |
!* |
上一条命令的所有参数 | echo a b c → print !* 输出 a b c |
!^ |
上一条命令的第一个参数 | — |
!n |
历史中第 n 条命令 | !100 执行第 100 条 |
!pattern |
最近一条以 pattern 开头的命令 | !git 执行最近的 git 命令 |
^old^new |
替换上一条命令中的文本 | ^foo^bar 把上一条的 foo 换成 bar |
2.4 历史配置
bash
# 历史文件与容量
HISTFILE=~/.zsh_history
HISTSIZE=50000 # 内存中保留的命令数
SAVEHIST=50000 # 写入文件的最大条数
# 去重与格式
setopt HIST_IGNORE_ALL_DUPS # 去除连续重复命令
setopt HIST_SAVE_NO_DUPS # 写入文件时也去重
setopt HIST_IGNORE_SPACE # 空格开头的命令不记录(适合敏感命令)
setopt SHARE_HISTORY # 多终端共享历史
3. 别名系统
Zsh 在 Bash alias 的基础上增加了 global alias 和 suffix alias,覆盖更多场景。
3.1 普通别名
bash
# 常用命令缩写
alias ll='ls -alh'
alias gs='git status'
alias gp='git push'
3.2 Global Alias
普通 alias 只能出现在命令开头,而 global alias 可以出现在命令的任意位置,会被全局替换:
bash
# 将管道常用操作定义为 global alias
alias -g G='| grep'
alias -g L='| less'
alias -g H='| head'
alias -g T='| tail'
alias -g W='| wc -l'
alias -g S='| sort'
alias -g N='2>/dev/null'
# 使用示例
dmesg G usb # 等价于 dmesg | grep usb
cat logfile L # 等价于 cat logfile | less
find / -name "*.log" N W # 等价于 find / -name "*.log" 2>/dev/null | wc -l
3.3 Suffix Alias
根据文件扩展名自动选择打开方式:
bash
# 定义后缀别名
alias -s py=vim # 直接输入 xxx.py 就用 vim 打开
alias -s md=code # .md 文件用 VS Code 打开
alias -s pdf=zathura # .pdf 文件用 zathura 打开
alias -s tar.gz='tar tzf' # 直接查看压缩包内容
# 使用示例:直接在终端输入文件名
# ./script.py → 自动用 vim 打开
# README.md → 自动用 VS Code 打开
4. 通配符与文件匹配
Zsh 的通配符(globbing)能力远超 Bash,无需 find 命令即可完成复杂文件匹配。
4.1 递归通配符 **
bash
# 匹配当前目录及所有子目录下的 .java 文件
ls **/*.java
# 匹配所有子目录下的 Makefile
cat **/Makefile
# 配合 ** 和目录限定符
ls **/src/ # 所有名为 src 的目录
需开启 GLOB_STAR_SHORT 选项才能单独使用 **(不含 *):
bash
setopt GLOB_STAR_SHORT # 允许 ** 单独匹配
4.2 限定符(Glob Qualifiers)
限定符写在 () 中,用于按文件类型、权限、大小等条件过滤:
| 限定符 | 含义 | 示例 |
|---|---|---|
*(.) |
仅普通文件 | ls *(.) |
*(/) |
仅目录 | ls *(/) |
*(x) |
有可执行权限的文件 | ls bin/(x) |
*(.x) |
普通文件 + 可执行 | ls *(.x) |
*(L0) |
空文件(大小为 0) | rm *(L0) |
*(L+1m) |
大于 1MB 的文件 | ls *(L+1m) |
*(m-7) |
7 天内修改过的文件 | ls *(m-7) |
*(om[1,5]) |
按修改时间排序取前 5 个 | ls *(om[1,5]) |
*(*.) |
可执行普通文件 | which **/*(.) |
bash
# 删除所有空目录
rmdir *(/^F) # / 表示目录,^F 表示非空取反(即空目录)
# 找出最近修改的 3 个文件
ls -lt *(om[1,3])
# 列出大于 100KB 的 .log 文件
ls **/*.log(L+100k)
4.3 否定与分组
bash
# ^ 取反:匹配不以 .bak 结尾的文件
ls ^*.bak
# 匹配 .py 或 .sh 文件
ls *.(py|sh)
需开启 EXTENDED_GLOB 选项:
bash
setopt EXTENDED_GLOB # 启用 ^ 取反和 # 等高级通配
5. 重定向与多命令操作
5.1 多命令连接
| 操作符 | 含义 | 示例 |
|---|---|---|
&& |
前一条成功才执行下一条 | mkdir foo && cd foo |
|| |
前一条失败才执行下一条 | cd foo || echo "目录不存在" |
; |
顺序执行,不管成功失败 | echo a; echo b |
& |
后台执行 | sleep 100 & |
5.2 多重重定向与 tee
bash
# 同时输出到终端和文件
make 2>&1 | tee build.log
# 将输出和错误分别写入不同文件
command > output.log 2> error.log
# Zsh 特有:同时重定向到多个目标
echo hello >file1 >file2 # 两个文件都写入 "hello"
5.3 Process Substitution
进程替换将命令的输出作为临时文件传给另一个命令,这是处理管道无法胜任场景的关键技巧:
bash
# 对比两个命令的输出(类似 diff 两个文件)
diff <(sort file1.txt) <(sort file2.txt)
# 将进程输出作为参数传递
wc -l <(grep "ERROR" app.log)
# 同时查看标准输出和错误
command > >(tee stdout.log) 2> >(tee stderr.log)
原理:<(command) 在 /dev/fd/ 下创建一个临时文件描述符,其他命令可以像读文件一样读取它。
6. 内建命令与变量操作
6.1 typeset 声明变量
typeset 是 Zsh 中声明变量的核心命令(declare、local、export 等都是它的别名或子集):
bash
typeset -i count=0 # 声明整数变量
typeset -a arr=(a b c) # 声明数组
typeset -A map=([k1]=v1 [k2]=v2) # 声明关联数组(字典)
typeset -r CONST=100 # 声明只读变量
typeset -x PATH # 导出为环境变量(等同于 export)
typeset -U path # 去重:path 数组自动去除重复路径
6.2 参数展开(Parameter Expansion)
Zsh 支持丰富的字符串操作,无需调用 sed 或 awk:
bash
name="hello_world.txt"
# 长度
echo ${#name} # 15
# 默认值
echo ${undefined:-default} # 输出 default
# 前缀/后缀删除
echo ${name#hello_} # world.txt(删除最短前缀)
echo ${name##*_} # world.txt(删除最长前缀)
echo ${name%.txt} # hello_world(删除最短后缀)
echo ${name%%.*} # hello_world(删除最长后缀)
# 替换
echo ${name/world/WORLD} # hello_WORLD.txt(首次替换)
echo ${name//_/ - } # hello - world.txt(全局替换)
# 大小写转换(Zsh 专属语法)
echo ${(U)name} # HELLO_WORLD.TXT(转大写)
echo ${(L)name} # hello_world.txt(转小写)
echo ${name:u} # HELLO_WORLD.TXT(转大写,简写形式)
6.3 数组操作
bash
arr=(apple banana cherry)
echo ${arr[1]} # apple(Zsh 数组从 1 开始,注意与 Bash 不同)
echo ${arr[-1]} # cherry(倒数第一个)
echo ${arr[2,3]} # banana cherry(切片)
echo ${#arr[@]} # 3(数组长度)
echo ${^arr}.log # apple.log banana.log cherry.log(逐元素扩展)
Zsh 数组下标从 1 开始,而 Bash 从 0 开始,这是两者的重要差异。
7. 插件与框架推荐
7.1 框架选择
| 框架 | 特点 | 适合场景 |
|---|---|---|
| oh-my-zsh | 社区最大、插件主题丰富、开箱即用 | 新手入门、快速配置 |
| zinit | 按需延迟加载(turbo mode),启动极快 | 追求启动速度的高级用户 |
| znap | 轻量极简,自动编译缓存,配置简洁 | 喜欢精简配置的用户 |
不建议同时使用多个框架,选一个即可。
7.2 必装插件
zsh-autosuggestions — 基于历史自动提示命令:
bash
# zinit 安装方式
zinit light zsh-users/zsh-autosuggestions
# 效果:输入命令时会自动灰度提示历史匹配
# 按 → 或 End 接受建议,继续输入则忽略
zsh-syntax-highlighting — 实时语法高亮:
bash
zinit light zsh-users/zsh-syntax-highlighting
# 效果:有效命令显示绿色,无效命令显示红色
# 路径存在时下划线标出,引号不匹配时标红
fzf — 模糊搜索神器(严格说是独立工具,但与 Zsh 深度集成):
bash
# 安装 fzf 及其 Zsh 集成
git clone --depth 1 https://github.com/junegunn/fzf ~/.fzf
~/.fzf/install
# Ctrl+T:模糊搜索文件并插入路径
# Ctrl+R:模糊搜索历史命令
# Alt+C:模糊跳转目录
7.3 实用插件清单
| 插件 | 功能 |
|---|---|
zsh-completions |
额外补全定义(cargo、pip、docker 等) |
z / zoxide |
智能目录跳转,根据访问频率排序 |
sudo |
双击 Esc 自动在命令前加 sudo |
copypath |
快速复制当前目录路径到剪贴板 |
dirhistory |
Alt+左/右箭头浏览目录历史 |
extract |
一条 extract 命令解压所有格式 |
8. 实用快捷键速查表
8.1 编辑快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl+A |
光标移到行首 |
Ctrl+E |
光标移到行尾 |
Ctrl+W |
删除光标前一个单词 |
Ctrl+U |
删除光标前全部内容 |
Ctrl+K |
删除光标后全部内容 |
Ctrl+Y |
粘贴最近删除的内容 |
Alt+. |
插入上一条命令的最后一个参数(等同于 !$) |
Ctrl+L |
清屏 |
Ctrl+_ |
撤销上一次编辑 |
8.2 进程控制快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl+C |
中断当前命令 (SIGINT) |
Ctrl+Z |
挂起当前命令,用 fg 恢复前台、bg 恢复后台 |
Ctrl+D |
发送 EOF,退出当前 Shell 或结束输入 |
8.3 常用组合技
bash
# 清屏并保留历史
Ctrl+L
# 杀掉占用端口的进程
kill $(lsof -ti:8080)
# 快速回到上一个工作目录
cd -
# 用 Alt+. 循环获取历史命令的参数
# 每按一次 Alt+. 就回溯更早的一条命令的最后一个参数
相关阅读
- [[正则表达式]] — 命令行中频繁使用正则进行文本处理
- [[Git]] — Git 的交互式操作依赖 Shell 环境
