Skip to content

⌨️ 卷④ 命令行与系统工具

20 条。适用场景:日常操作效率、本地环境搭建、构建与打包

「要点」「我的补充」为本人撰写,非原文摘录。

← 返回资料库总览


一、终端与 Shell:那些没人明说的规则

61. New zine: The Secret Rules of the Terminal

来源:Julia Evans · jvns.ca 读它解决什么:终端里那些"莫名其妙"的行为——按键失灵、颜色错乱、程序卡住——背后其实有一套规则。

要点

  • 终端是多层叠加的:终端模拟器 → 伪终端(pty)→ 行规则(line discipline)→ shell → 程序,任何一层都能改变你看到的行为
  • 很多困惑来自职责错位:Ctrl-C 是行规则送信号,不是程序自己处理的;Tab 补全是 shell 干的,不是终端
  • 转义序列决定颜色与光标,程序崩溃后终端"乱掉"通常是转义状态没复位

我的补充:终端乱掉别关窗口,敲 reset(看不见输入也照敲,回车)能恢复。stty sane 是更轻的版本。另一个高频困惑:管道后颜色消失——那是程序检测到输出不是 tty 主动关掉的,多数命令有 --color=always 强制开启(配 less -R 才能正确显示)。

阅读原文 →


62. What helps people get comfortable on the command line?

来源:Julia Evans · jvns.ca 读它解决什么:想帮团队新人(或自己)真正上手命令行,而不是背命令。

要点

  • 不适感往往来自不可逆的恐惧:怕敲错删掉东西,所以不敢试
  • 有效的缓解手段是提供安全的试验环境与可回退的操作习惯
  • 知道"怎么查"比记住命令更重要:--helpmantldr 的分工

我的补充:三个能立刻降低风险的习惯:一是 rm 先用 ls 确认同样的通配符匹配到什么(ls *.logrm *.log);二是危险命令加 -i 或先 echo 出来看;三是 alias rm='rm -I'(大写 I,批量删才提示,比 -i 不烦人)。给新人开一台可以随便重装的机器,比任何教程都有效。

阅读原文 →


63. Reasons I still love the fish shell

来源:Julia Evans · jvns.ca 读它解决什么:在考虑换 shell,想知道 fish 的实际收益在哪。

要点

  • fish 的核心卖点是开箱即用的交互体验:基于历史的自动建议、语法高亮、无需配置的补全
  • 代价是不兼容 POSIX 语法,网上抄的 bash 片段常常跑不通
  • 定位是"交互 shell",脚本仍建议写 POSIX sh 或 bash

我的补充:这个取舍很清楚:交互用 fish,脚本写 #!/usr/bin/env bash,两者不冲突。不想换 shell 又想要类似体验,bash 装 ble.sh、zsh 装 zsh-autosuggestions + zsh-syntax-highlighting 能拿到八成。服务器上别装 fish——救援场景下你能指望的只有 sh

阅读原文 →


64. Notes on switching to Helix from vim

来源:Julia Evans · jvns.ca 读它解决什么:在评估现代终端编辑器,想知道从 vim 迁移的实际体验。

要点

  • Helix 的差别在操作顺序:选择在前、动作在后(selection → action),与 vim 的 verb → object 相反
  • 开箱自带 LSP 与语法树支持,不需要堆插件
  • 迁移成本主要是肌肉记忆,不是功能缺失

我的补充:现实建议:服务器上仍然要会 vi 的基本操作i/Esc/:wq/dd),因为救援环境只有它。本地编辑器可以随便换。如果只是嫌 vim 配置麻烦,nvim 加一个成品配置(LazyVim/AstroNvim)比换编辑器成本更低。顺手记一条:vi:set paste 再粘贴,否则自动缩进会把代码搞乱。

阅读原文 →


65. A list of new(ish) command line tools

来源:Julia Evans · jvns.ca 读它解决什么:想知道有哪些新工具值得替换掉手上的老命令。

要点

  • 这类列表的价值是发现你不知道自己需要的工具,比如 fd(替代 find)、rg(替代 grep)、jqfzfbatdust
  • 多数新工具的共同点是默认行为更合理(自动忽略 .git、自带彩色、并行)
  • 老命令仍需会用:新工具不一定在目标机器上有

我的补充:投资回报最高的两个是 rgfzfrggrep -r 快一个量级且默认遵守 .gitignorefzf 装完把 Ctrl-R 历史搜索换掉,日常收益立刻可感。但脚本里别用这些——目标机器不一定有,写脚本仍然用 grep/find/sed。我在这个博客里搜代码用的就是 ripgrep。

阅读原文 →


66. Things that used to be hard and are now easy

来源:Julia Evans · jvns.ca 读它解决什么:提醒自己有些"众所皆知很麻烦"的事其实早就变简单了。

要点

  • 技术常识会过期:HTTPS 证书、容器化本地环境、静态站托管,这些当年的苦活现在几分钟搞定
  • 沿用旧方法的成本常常是隐性的——你不知道有更省事的路
  • 定期重新评估工具链是有价值的

我的补充:最典型的就是证书:现在用 Caddy 或 Cloudflare,HTTPS 是零配置的,还有人在手工续期。另一个是静态站:Cloudflare Pages / Netlify 免费额度对个人站完全够用,不必自己维护 nginx 和服务器——这个博客就是这么部署的。每年花一小时问一次"我现在做的哪件事其实已经不必手工做了",回报很高。

阅读原文 →


67. Some tiny personal programs I've written

来源:Julia Evans · jvns.ca 读它解决什么:给"要不要为这个小麻烦写个脚本"提供一个参考答案:要。

要点

  • 小工具的价值不在通用性,而在恰好贴合你自己的工作流
  • 几十行的脚本往往比找一个大而全的工具更快解决问题
  • 这类程序不需要考虑别人怎么用,可以极度简化

我的补充:建议给自己建一个 ~/bin 并加进 PATH,脚本随手丢进去。两个提醒:一是第一行写清 #!/usr/bin/env bashchmod +x;二是哪怕只给自己用也加一行注释说明用途,半年后你不会记得 fixup.sh 是干什么的。这类脚本值得纳入你的 dotfiles 仓库。

阅读原文 →


二、构建与编译

68. Using make to compile C programs (for non-C-programmers)

来源:Julia Evans · jvns.ca 读它解决什么:需要从源码编译一个工具,但完全不懂 C 的构建流程。

要点

  • make 的本质极简:目标、依赖、命令,依赖比目标新就重新执行
  • 隐式规则会让简单情况下不写规则也能编译,这也是它看起来神秘的原因
  • 编译失败最常见的原因是缺头文件(-dev/-devel 包)而不是代码问题

我的补充:编译报错先看第一条错误,不是最后一条——后面的多是连锁反应。缺头文件的报错形如 xxx.h: No such file,装对应 -dev 包即可。Makefile 里命令必须用 Tab 缩进,空格会报 "missing separator",这个坑几乎每个人都踩过一次。并行编译用 make -j$(nproc) 能快很多,但报错信息会交错,调试时改回 -j1

阅读原文 →


69. ninja: a simple way to do builds

来源:Julia Evans · jvns.ca 读它解决什么:想理解为什么现代项目用 ninja 而不是直接用 make。

要点

  • ninja 刻意不做"人写"的设计:它是 CMake/Meson 等生成器的输出目标,专注于把增量构建做到最快
  • 因此 ninja 文件很啰嗦但极其明确,没有隐式规则
  • 速度优势主要来自精确的依赖信息与高效的调度

我的补充:实用结论:用 CMake 时加 -G Ninja,大项目增量构建能明显快过 Makefile 生成器。检查是否装了:ninja --version。另外 ninja 默认就是并行的,不需要 -j;想限制并发用 -j N(内存小的机器上编译 C++ 项目常需要限制,否则会 OOM)。

阅读原文 →


70. entr: rerun your build when files change

来源:Julia Evans · jvns.ca 读它解决什么:想要"改文件就自动重跑测试/构建",又不想装一套 watcher 框架。

要点

  • entr 从 stdin 读文件列表,文件变化就执行命令,组合性极强
  • 典型用法是 find/ls/git ls-files 管道给它
  • 相比语言专属的 watch 工具,它与语言无关

我的补充:常用式:git ls-files | entr -c pytest-c 每次先清屏)。要重启长驻进程加 -rgit ls-files | entr -r python app.py。注意 entr 不会自动发现新增文件——文件列表是启动时定的,新建文件后要重启它。这点是它和 nodemonwatchexec 的主要差别,watchexec 更适合频繁新建文件的场景。

阅读原文 →


71. Some notes on using esbuild

来源:Julia Evans · jvns.ca 读它解决什么:前端构建慢得难受,想知道 esbuild 能不能救。

要点

  • esbuild 用 Go 编写并大量并行,构建速度比传统 JS 工具链快一到两个数量级
  • 代价是生态与插件体系不如 webpack 完整,复杂需求可能不好满足
  • 定位常常是"底层构建器",被 Vite 等工具内部使用

我的补充:这条与这个博客直接相关——VitePress 底层是 Vite,而 Vite 的依赖预打包用的就是 esbuild,这是 docs:dev 冷启动快的原因之一。要注意 esbuild 不做类型检查,它只是把 TS 的类型擦掉;类型错误必须靠单独跑 tsc --noEmitvue-tsc 才能发现,别以为构建通过就类型没问题。

阅读原文 →


72. SQLite is really easy to compile

来源:Julia Evans · jvns.ca 读它解决什么:想要一个"从源码编译"的成功体验,或需要定制编译 SQLite。

要点

  • SQLite 以合并单文件(amalgamation)分发,一条 gcc 命令就能编出来,没有依赖地狱
  • 这种分发方式是刻意设计,为的是极致的可移植性
  • 定制编译常见诉求是开启可选模块(FTS5 全文检索、JSON1、R-Tree)

我的补充:想拿全文检索就编译时加 -DSQLITE_ENABLE_FTS5。检查现有 sqlite 支持哪些特性:sqlite3 -cmd "pragma compile_options;" ""。这也是从源码编译的最佳入门练习——成功率接近 100%,适合先在它上面建立信心,再去啃那些依赖复杂的项目。

阅读原文 →


三、虚拟机、容器与沙箱

73. Lima: a nice way to run Linux VMs on Mac

来源:Julia Evans · jvns.ca 读它解决什么:Mac 上需要真 Linux 环境(不只是 Docker),想要低摩擦方案。

要点

  • Lima 在 macOS 上跑 Linux 虚拟机并自动处理文件共享与端口转发
  • 它也是 Docker Desktop 的常见替代路径(配合 containerd/nerdctl)
  • 相比手工 QEMU,省掉了大量配置

我的补充:Mac 用户想脱离 Docker Desktop 授权限制,Lima + nerdctl 或 colima 是主流选择,colima start 之后 docker CLI 直接可用。注意文件共享性能是虚拟机方案的通病——挂载大量小文件(node_modules)时明显慢,尽量把工作目录放在 VM 内部,或用虚拟机原生的卷。

阅读原文 →


74. Notes on running containers with bubblewrap

来源:Julia Evans · jvns.ca 读它解决什么:只想沙箱化跑一个不可信程序,不需要完整的容器运行时。

要点

  • bubblewrap 是轻量的非特权沙箱工具,直接用 Linux 命名空间构建隔离环境
  • 相比 Docker,它没有镜像、网络编排这些概念,启动开销极小
  • Flatpak 底层用的就是它

我的补充:适合的场景是"跑一个来源不明的二进制,但不想让它读我的家目录"。最小用法:bwrap --ro-bind /usr /usr --dev /dev --unshare-all -- <命令>。注意默认什么都不给,需要的路径要显式 bind,这与 Docker 的思路正好相反(Docker 是默认隔离好再开洞)。这也让它更容易审计。

阅读原文 →


75. Firecracker: start a VM in less than a second

来源:Julia Evans · jvns.ca 读它解决什么:需要虚拟机级别的隔离,但不能接受虚拟机的启动时间。

要点

  • Firecracker 是为 serverless 设计的轻量 VMM,砍掉了绝大多数设备模拟以换取极快启动
  • 它提供的是硬件级隔离,比容器的命名空间隔离强得多
  • AWS Lambda / Fargate 的底层技术

我的补充:选型判据很清晰:跑不可信的第三方代码(多租户平台、在线代码执行)就该用 microVM 而不是容器,容器逃逸的历史 CVE 数量说明命名空间隔离不足以对抗恶意代码。自己业务的服务用容器完全够。想在自己机器上试需要 KVM 支持:ls /dev/kvm,云主机上通常需要开嵌套虚拟化。

阅读原文 →


76. Docker Compose: a nice way to set up a dev environment

来源:Julia Evans · jvns.ca 读它解决什么:本地要起数据库、缓存、应用好几个服务,不想手工管。

要点

  • Compose 把多容器编排写成一个声明式文件,一条命令起停
  • 对开发环境的核心价值是可复现:新人克隆仓库就能起环境
  • 网络与依赖顺序由 Compose 处理,服务间用服务名互访

我的补充:一个必须知道的现实问题:Compose v1(Python 版,命令是 docker-compose)已停止维护,与新版 Docker 不兼容。我在自己的一台服务器上就踩过——v1 配 Docker 29 执行 up 会把容器删掉又建不回来。要用 v2(插件版,命令是 docker compose,中间是空格)。查版本:docker compose version。另外 depends_on 只保证启动顺序不保证服务就绪,要就绪判断得配 healthcheckcondition: service_healthy

阅读原文 →


四、声明式配置:Nix 这条路

77. Some notes on using nix

来源:Julia Evans · jvns.ca 读它解决什么:听说 Nix 能解决环境不一致,想知道入门体验如何。

要点

  • Nix 的核心是内容寻址的包存储:每个包按其完整依赖的哈希存放,不同版本可共存
  • 由此得到的能力是精确可复现的环境,不依赖全局状态
  • 学习曲线主要来自它自己的语言与概念(derivation、store、profile)

我的补充:最低成本的收益方式:只用 nix-shell -p <包> 临时获得某个工具,用完即走,不污染系统。比如需要一次性用某个特定版本的 Node,nix-shell -p nodejs_20 就够了。不必一上来就 NixOS,那是完全不同量级的投入。多用户安装还要注意 /nix 目录占空间,定期 nix-collect-garbage -d

阅读原文 →


78. How do Nix builds work?

来源:Julia Evans · jvns.ca 读它解决什么:想理解 Nix 的可复现性到底靠什么实现。

要点

  • 构建在沙箱里进行:无网络、限定输入、固定时间戳,以消除不确定性
  • 每个构建产物的路径包含输入哈希,输入变了路径就变,因此不存在"覆盖安装"
  • 可复现性来自"把所有输入显式化"这一强制约束

我的补充:这个思路值得借用到任何构建系统:不可复现的根因几乎总是"隐式输入"——当前时间、网络下载、宿主机上恰好装了的库、环境变量。CI 里排查"本地能过 CI 不过"就按这个清单查。Docker 构建里对应的做法是锁定基础镜像 digest(不用 :latest)、依赖用 lockfile、--build-arg 显式传参。

阅读原文 →


79. Some notes on nix flakes

来源:Julia Evans · jvns.ca 读它解决什么:Nix 生态里 flakes 是什么、要不要用。

要点

  • flakes 给 Nix 加了标准化的输入声明与 lockfile(flake.lock),解决了此前依赖版本漂移的问题
  • 有了 lockfile 才真正做到"别人克隆你的仓库能得到同样环境"
  • 长期处于实验特性状态,但事实上被广泛使用

我的补充:如果你要用 Nix 管项目环境,直接从 flakes 开始,别学老式 default.nix 那套。需要在配置里开启:experimental-features = nix-command flakesflake.lock 必须提交进仓库——这和 package-lock.jsonpnpm-lock.yaml 是同一个道理,不提交就失去了全部意义。

阅读原文 →


80. Some notes on NixOS

来源:Julia Evans · jvns.ca 读它解决什么:评估把整个操作系统交给声明式配置管理的实际体验。

要点

  • NixOS 把系统配置写成一个文件,重建即生效,且可以回滚到上一个代号(generation)
  • 优势在服务器场景明显:配置即代码,重装等于重放配置
  • 代价是遇到"不按 FHS 来"的软件(预编译二进制、专有驱动)时会很痛苦

我的补充:可回滚这一点在服务器上非常有价值——改配置改坏了,重启选上一个 generation 就回去了,比快照轻。但不建议贸然把生产机换成 NixOS:生态摩擦是真实成本,尤其国内很多软件只提供 deb/rpm。想要类似收益又不想跳这么远,用 Ansible 管配置 + 定期快照,收益的八成能拿到。

阅读原文 →


本卷小结

三条:

  1. 交互和脚本分开。交互 shell 随便折腾(fish/zsh + 现代工具),脚本坚持 POSIX/bash,救援环境只有 sh
  2. docker-composedocker compose 不是一回事。v1 已停维护且与新 Docker 不兼容,会删掉容器建不回来。
  3. 不可复现的根因是隐式输入。锁定基础镜像 digest、提交 lockfile、别在构建里联网下东西。

← 上一卷:Kubernetes 与容器 · 返回总览 · 下一卷:数据库与存储 →