PATH 里的波浪号未必是你的 HOME

在 shell 命令中使用 `~`——尤其是在修改 `PATH` 时——的行为可能与许多人的预期大不相同,因为波浪号展开只在特定的未加引号位置发生,而且在 POSIX shell 与 Bash/Zsh 扩展之间也不一致。评论者分享了诸如把字面量 `~` 误插入 `PATH`,甚至误删 `$HOME` 之类的坑,并讨论用户本地目录是否应排在系统路径之前,同时将 Bash 众多“陷阱”与 fish、nushell、zsh 等替代 shell 作对比。这场讨论凸显了细微的引号与展开规则,再加上不一致的工具和文档,使得稳健的 shell 使用与脚本编写比表面上更困难。

波浪号展开与 PATH 行为

  • 波浪号只会在特定位置展开(未加引号的“单词”开头;在某些 shell 中,赋值中未加引号的冒号后面也会展开)。
  • 给 ~ 加引号会阻止展开,并可能让 PATH 里保留字面量 ~,这就是原始问题。
  • 某些 shell(zsh、fish)提供了更方便或基于数组的方式把 ~/.local/bin 加到 PATH 中,能正确处理展开。
  • 几位评论者更喜欢在脚本里用 $HOME 而不是 ~,以避免意外。

引号规则与常见 shell 陷阱

  • 误解何时该加引号是 bug 的主要来源:人们既会过度加引号,也会加得不够。
  • 给出的建议:
    • 在参数中总是给变量展开加引号("$var"),以避免单词拆分和通配展开。
    • 只在包含特殊字符的字面量字符串上使用单引号。
  • 变量展开和波浪号展开的行为不同;把它们当成一样会导致错误。

PATH 的顺序与安全性

  • 对于是否应把 ~/.local/bin 这类用户目录放在前面还是后面,存在争论。
    • 一派主张追加到后面,让系统二进制优先,以降低恶意覆盖的风险。
    • 另一派主张放在前面,这样用户可以有意覆盖过时的系统工具。
  • 普遍共识是:如果攻击者能写入你的 PATH 目录,那你已经遭遇严重入侵了。

POSIX 与 shell 特有行为

  • 文章中的某些行为依赖 bash/zsh 扩展,对 /bin/sh(通常是 dash 或 ash)并不具备可移植性。
  • 评论中引用了 POSIX 的波浪号展开规则;起初有些混淆,后来澄清在赋值中未加引号的 : 后面是允许展开的。
  • 多次提醒要区分“bashism”和严格符合 POSIX 的构造。

替代 shell 与语言选择

  • 很多人批评 bash 是一种“糟糕”或脆弱的脚本语言,边界情况太多。
  • 提到的替代方案包括:fish、zsh、nushell、murex、PowerShell、Perl、Ruby 等。
  • 反方观点是:bash/sh 之所以占主导,是因为它们几乎到处都预装,尤其是在远程系统上。

文件名、字符与健壮性

  • 有人认为如果路径只允许受限的 ASCII 集合,生活会更简单,这样能避免编码和解析问题。
  • 也有人强烈支持非拉丁脚本和任意 Unicode,尽管这会给工具带来麻烦。
  • 文件名中包含空格或以 - 开头被指出是 bug 和安全隐患的常见来源。

环境、HOME 与调试

  • 有人指出 $HOME 与系统数据库中的账户 home 目录并不完全相同;二者可能不一致,并让 ~ 的解析变得混乱。
  • 为测试而修改 HOME 可能会与以不同方式解析 home 目录的工具发生冲突。
  • 大型组织通常拥有层层嵌套的 shell 启动文件,很难追踪变量到底在哪里被设置;因此有人推荐使用 shell 启动追踪工具。

真实事故与经验教训

  • 有多个轶事:创建了字面量的 ~ 目录、误执行 rm -r ~、以及 AI 工具创建 ~ 目录。
  • 总结出的教训包括:尽量避免使用 rm -r,使用更明确的路径(./~),并谨慎对待 shell 特性。