Zsh使用技巧

Zsh使用技巧

cc|2026年5月20日 · 18 分钟

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 cprint !* 输出 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 aliassuffix 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 中声明变量的核心命令(declarelocalexport 等都是它的别名或子集):

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 支持丰富的字符串操作,无需调用 sedawk

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 环境