我在终端里待时间可能比在浏览器里还多。有些事情在命令行里就是快。
这篇文章记录我目前在用工具链。不是教程,是我实际在用配置和习惯。你可能会发现一些地方可以借鉴,也可能觉得某些选择很奇怪。都正常,工具是长在手上。
tmux:终端里窗口管理器
我以前不用 tmux。觉得开多个终端窗口就行了,为什么要在一个终端里再套一层。
后来同时跑任务多了:ssh 连服务器、本地开发服务器、数据库客户端、git 操作、日志查看。窗口切来切去,找不到哪个是哪个。
tmux 解决的问题是:把多个会话装进一个终端窗口。
我的 tmux 配置
我用的是 oh-my-tmux 作为基础配置,然后改了几处。
~/.tmux.conf.local 里我改了这些:
# ~/.tmux.conf.local
# 改用 Ctrl+a 作为前缀键,Ctrl+b 太别扭
set-option -g prefix C-a
unbind-key C-b
bind-key C-a send-prefix
# 鼠标支持(选文本、滚屏)
set -g mouse on
# 窗口编号从 1 开始,0 在左边太远
set -g base-index 1
setw -g pane-base-index 1
# 更长的历史记录
set -g history-limit 10000
# 分割面板的快捷键(模仿 vim)
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
-c "#{pane_current_path}" 这个很重要。默认情况下,新分割面板会停留在用户目录,而不是当前目录。加上这个,新面板继承当前路径。
我常用操作
我的工作流一般是这样:一个 tmux 会话对应一个项目。
# 创建或重新连接项目会话
tmux new-session -s myproject -d # 后台创建
tmux attach -t myproject # 连接
# 或者直接:如果会话存在就连接,不存在就创建
tmux attach -t myproject || tmux new -s myproject
我在用快捷键组合:
Ctrl+ac— 创建新窗口Ctrl+a1-9— 切换窗口Ctrl+a%— 水平分割(我改成了|,更好记)Ctrl+a"— 垂直分割(我改成了-)Ctrl+a方向键— 切换面板Ctrl+az— 最大化/恢复当前面板(临时需要大视野时用)Ctrl+a[— 进入复制模式,可以用鼠标滚屏
有一个操作我一开始不习惯:detach 之后会话还在跑。我以前会开着终端不关,现在直接 Ctrl+a d 退出,第二天连回来,一切都在。
zsh 和 oh-my-zsh
我用 zsh 不是因为它比 bash 强多少,而是 oh-my-zsh 的插件生态省事。
我的 .zshrc 精简版
# ~/.zshrc
export ZSH="$HOME/.oh-my-zsh"
# 主题(我用的是 powerlevel10k,但这是另一个话题)
ZSH_THEME="robbyrussell"
# 我实际在用的插件
plugins=(
git
docker
docker-compose
node
npm
python
zsh-autosuggestions
zsh-syntax-highlighting
fzf
)
source $ZSH/oh-my-zsh.sh
# 下面是我自己的配置
主题我用是简单 robbyrussell。之前用过 powerlevel10k,显示信息很多,但我觉得干扰也多。现在只要一个当前目录和 git 分支就够了。
两个插件值得单独说
zsh-autosuggestions:输入命令时,会根据历史记录灰色显示建议。按 → 接受建议。这个插件帮我节省了很多重复输入。
zsh-syntax-highlighting:命令输错会显示红色。在按回车之前就知道命令有没有问题。
这两个插件都可以通过 oh-my-zsh 安装:
# autosuggestions
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
# syntax-highlighting
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
fzf:模糊搜索改变了一切
fzf 是一个通用模糊搜索工具。它可以搜索文件、命令历史、进程、git 提交,几乎任何东西。
安装和初始配置
# 安装(macOS)
brew install fzf
# 安装(Linux)
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
# Windows 可以用 scoop 或 chocolatey
scoop install fzf
安装时它会问你要不要添加按键绑定和补全,选是。
我每天都在用 fzf 操作
搜索文件:
# Ctrl+t 触发(这是 fzf 默认的按键绑定)
# 在命令行里按 Ctrl+t,会弹出文件搜索
# 输入部分文件名,选中后按回车,路径会插入到命令行
搜索命令历史:
# Ctrl+r 触发
# 输入关键词,搜索历史命令
# 我常用这个找回之前跑过的长命令
在 vim 里搜索文件(如果你用 vim):
" 在 .vimrc 里添加
set rtp+=~/.fzf
nnoremap <C-p> :Files<CR>
按 Ctrl+p 搜索项目里文件。比手动输入路径快。
fzf 结合其他工具
fzf 本身是搜索界面,真正强大是和别工具组合。
搜索 git 提交:
git log --oneline | fzf --preview 'git show {+1}'
--preview 会在上方显示选中项详情。我第一次看到这个效果时,觉得命令行也可以很直观。
搜索进程并 kill:
ps aux | fzf --multi | awk '{print $2}' | xargs kill -9
--multi 允许选多个。不过这个操作有风险,我一般只用 kill 的交互模式(kill <PID>),不用批量。
fd、rg 和其他现代化工具
这些工具共同点是:它们做了和原有工具一样事情,但更好用。
fd 替代 find
find 命令的语法我一直记不住。每次要用都得查。
# 查找所有 .js 文件
# 旧的 find 方式
find . -name "*.js"
# fd 方式
fd -e js
fd 默认会忽略 .gitignore 里的文件。这很好,我一般不想搜到 node_modules 里的东西。
常用参数:
fd # 列出所有文件(递归)
fd -e md # 找所有 markdown 文件
fd -t f "readme" # 找文件名包含 readme 的文件
fd -t d "src" # 找目录
fd -H "config" # 包含隐藏文件
rg(ripgrep)替代 grep
grep -r 搜代码很慢,而且常常搜到不该搜地方。
# 在代码里搜索 "function"
# grep 方式
grep -r "function" .
# rg 方式
rg "function"
rg 的特点:
- 自动忽略
.gitignore里的文件和目录 - 自动识别
.rgignore(类似.gitignore) - 速度快(用多线程搜索)
- 默认彩色输出,匹配部分高亮
我常用:
rg "TODO" # 找代码里的 TODO
rg -i "error" # 不区分大小写
rg -w "main" # 全词匹配(不匹配 "maintask" 之类的)
rg --type js "import" # 只在 js 文件里搜
--type 参数会自动识别文件类型。支持几百种语言,不用手动写 -e js -e ts -e jsx。
bat 替代 cat
cat 只是把文件内容打印出来。bat 会加上语法高亮和行号。
bat README.md # 带语法高亮的查看
bat -n file.js # 显示行号
bat -A file.js # 显示不可打印字符(调试时用)
我还把 bat 设为了 man 的分页器:
# ~/.zshrc
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
现在 man 页面也有语法高亮了。
exa 替代 ls(或 eza)
exa 是 ls 的现代化替代品,彩色输出、图标、git 状态集成。
exa --icons -l # 列表形式,带图标
exa --icons -T # 树形显示目录结构
exa --icons -l --git # 显示 git 状态
注意:exa 已经停止维护。它的分支 eza 在继续开发。
# 安装 eza
brew install eza # macOS
scoop install eza # Windows
我把 ls 别名到了 eza:
alias ls="eza --icons"
alias ll="eza --icons -l"
alias tree="eza --icons -T"
alias 和函数技巧
alias 和函数是在减少重复输入。我以前不太用,觉得记 alias 比记原命令更麻烦。后来发现,alias 是用来记那些你频繁用命令的。
我的 alias 清单
# ~/.zshrc
# 目录跳转
alias ..="cd .."
alias ...="cd ../.."
alias ~="cd ~"
# 编辑器
alias v="vim"
alias c="code ." # VS Code 打开当前目录
# git 缩写(这些 oh-my-zsh 的 git 插件也提供了,但我习惯用这些)
alias gs="git status"
alias ga="git add"
alias gc="git commit"
alias gp="git push"
alias gl="git pull"
alias gd="git diff"
# docker(容器多了之后,这些很省事)
alias dps="docker ps"
alias dpsa="docker ps -a"
alias di="docker images"
alias dex="docker exec -it"
# 系统
alias h="history"
alias cl="clear"
alias path="echo $PATH | tr ':' '\n'" # 查看 PATH,每行一个
函数比 alias 更灵活
alias 只能做简单替换。函数可以接受参数、做条件判断。
智能解压函数:
# ~/.zshrc
extract() {
if [ -f $1 ]; then
case $1 in
*.tar.bz2) tar xjf $1 ;;
*.tar.gz) tar xzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar e $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xf $1 ;;
*.tbz2) tar xjf $1 ;;
*.tgz) tar xzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' 无法解压" ;;
esac
else
echo "'$1' 不是有效文件"
fi
}
不管什么压缩格式,都用一个命令:extract file.tar.gz。
快速创建并进入目录:
mkcd() {
mkdir -p "$1" && cd "$1"
}
在 vim 里打开当前 git 项目的 root:
vg() {
local root=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -n "$root" ]; then
vim "$root/$1"
else
vim "$1"
fi
}
最常用快捷键组合
这些是我在终端里手不离操作。
tmux:
Ctrl+ad— detach(退出但保持会话)Ctrl+ac— 新建窗口Ctrl+an/p— 下一个/上一个窗口Ctrl+a}— 交换面板位置
命令行编辑(在 zsh/bash 里都有效):
Ctrl+a— 光标移到行首Ctrl+e— 光标移到行尾Ctrl+w— 删除光标前一个单词Ctrl+k— 删除光标到行尾Ctrl+u— 删除行首到光标Ctrl+r— 搜索历史(fzf 增强版)Alt+b/Alt+f— 按单词后退/前进
fzf:
Ctrl+t— 搜索文件,结果插入命令行Alt+c— 搜索目录,直接 cd 过去Tab— 多选模式
我一开始记不住这么多。选几个你每天都会用,练成肌肉记忆,再往下加。
踩过的坑
不要在 tmux 里嵌套 tmux。我在服务器上用 tmux,本地也用 tmux,按键冲突很痛苦。现在的做法是:本地用 tmux 管理窗口,连服务器时直接用 ssh,不在服务器 tmux 里操作。或者,如果必须用服务器 tmux,本地 tmux 用 Ctrl+a 作为前缀,服务器上用 Ctrl+b,区分开。
oh-my-zsh 插件不是越多越好。我以前装了一堆插件,启动变慢。现在只留实际在用。启动时间从 3 秒降到了不到 1 秒。可以用 time zsh -i -c exit 测试启动时间。
fzf 的预览功能会拖慢大文件搜索。如果搜索结果很多,--preview 可能会卡。这时候可以按 ? 查看帮助,或者暂时关掉预览(Ctrl+/ 切换)。
总结
这套工具链我迭代了几年。每次加新工具,都会问自己:它解决是什么问题?如果只是为了用而用,我会删掉。
工具是手段。如果现在配置让你在终端里觉得顺手,那就够了。不用追新,也不用什么都用。
相关资源:
种下你的想法
在花园里留下一条评论,和这篇文章一起生长。