Hyaika Blog

Penguin is all you need

设计

那个叫「竖线」的符号:一条线,既连接一切,又分隔一切

那个叫「竖线」的符号:一条线,既连接一切,又分隔一切

那个叫「竖线」的符号:一条线,既连接一切,又分隔一切

目录

  • 贝尔实验室那条最省的线
  • 连接:把 A 的出口,接进 B 的入口
  • 分隔:被夹起来的,是「内部」
  • 表格:竖线画出来的格子
  • 边界,既是连接也是分隔
  • 我把 8160 个竖线,按工种分了一次类

同一个字符,有两种画法。

A | B——竖线站在两个东西中间。ps aux | grep node,一行命令,两个进程被它接在一起,前一个的输出直接灌进后一个的输入。

|A|——竖线把东西夹在中间。|-3| 的意思是 3:不是「负三」,是「负三离零有多远」。

第一种画法里,它是连接符。第二种画法里,它是分隔符。同一个字符,一个键按出来的同一根线。

而这,恰好是边界的定义。

贝尔实验室那条最省的线

竖线不是被设计出来的。它是捡来的。

打字机时代,键盘上有一批「没被分配正经工作」的字符:#、@、&、%、~、|。它们的 ASCII 码位是 0x23、0x40、0x26、0x25、0x7E、0x7C——排在字母数字后面,像是字母表收工后剩下的边角料。

1960 年代,贝尔实验室的 Doug McIlroy 在一份备忘录里写了一个想法:程序应该像水管一样,一个的输出接进下一个的输入,而连接它们的,就是这条竖线。后来 Ken Thompson 在 Unix 里把它变成了现实。

这个想法后来被称为 Unix 哲学:每个程序只做一件事,做好它;程序之间的协作,靠管道完成。

也就是说——这个符号的出现,比它连接的 Unix 还早。它是整个 Unix 世界观的语法标记。

有意思的是,McIlroy 当年发明的是「管道」这个概念,不是竖线本身。竖线在键盘上躺了几十年,直到有人发现「两个程序之间那个口子」,恰好可以用这条没人要的线来画。

连接:把 A 的出口,接进 B 的入口

管道的机制今天还在被几十亿人每天触发,只是没人会停下来看它一眼。

echo 'hello' | wc -c
# 6

echo 把 hello 打出来,wc -c 数了数——6 个字节(hello\n)。中间那条竖线,把前一个进程的 stdout 接进了后一个进程的 stdin。

ls /usr/bin | grep -c '^py'
# 16

这台机器上,/usr/bin 里以 py 开头的程序有 16 个。ls 列出来,grep 过滤,-c 计数——三个进程,两条竖线。

ps aux | grep -i node | grep -v grep | wc -l
# 1

四段管道。ps 列出所有进程,grep 筛出 node,grep -v 去掉 grep 自己,wc -l 数行。每一条竖线,都是一次进程间的握手。

在管道之前,程序之间交换数据要靠临时文件:A 写一个文件,B 读那个文件,然后有人负责删掉它。管道把这套「先落盘再读取」的仪式压缩成了一个字符。

一个字符,取代了一整个文件系统操作。这是符号史上性价比最高的一次征用。

分隔:被夹起来的,是「内部」

竖线的另一面,是分隔。

数学里,|-3| 读作「负三的绝对值」。它问的不是「负三是几」,而是「负三离零有多远」——答案是 3。两条竖线把数字夹在中间,像是在说:里面的东西,请单独看。

同样的逻辑,在 20 世纪初被 Sheffer 借去表示逻辑学里的 NAND——「not both」,不是两者都成立。两条线把两个命题夹在一起,表示「它们不能同时为真」。

正则表达式里,cat|dog 的意思是「匹配 cat 或者 dog」——竖线在这里是分隔符,把两个候选选项隔开。Python 实测:

import re
re.findall(r'cat|dog', 'a cat and a dog')
# ['cat', 'dog']

位运算里,5 | 3 等于 7——二进制 101 | 011 = 111。竖线在这里是「或」,把两股二进制流合并成一股。这跟管道是同一件事的两种说法:管道是进程级的「或」,位或是数据级的「或」。

有意思的是,竖线做分隔符时,恰好也在做连接:绝对值把「内部」从「外部」隔开,但正因为它隔开了,内部才成其为内部。正则的 cat|dog 把两个选项分开,但正因为它分开,两个选项才能同时存在于一条规则里。

分隔,是另一种形式的连接。

表格:竖线画出来的格子

如果你读到这里,你正在看一个由竖线组成的表格——不对,你正在看一个由竖线组成的目录。

Markdown 表格是竖线最著名的「民用」岗位:

| 维度 | 在家 | 咖啡店 |
|------|------|--------|
| 专注度 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 成本 | 0 | 一杯桂花拿铁 |

竖线在这里既不连接进程,也不夹数字——它画格子。每一列被竖线隔开,但正因如此,行与行才能对齐成一张表。没有竖线,这些内容只是一堆散落的词。

我扫了自己的博客数据库:全库 548 篇已发布文章里,166 篇正文含竖线,总共 2787 个——而且绝大多数是表格分隔符。也就是说,竖线在我自己的写作里,干的是一份「排版工人」的活。

边界,既是连接也是分隔

到这里,竖线的所有工种可以并成一排看:

工种 竖线在做什么 连接 or 分隔
Unix 管道 ps | grep 把两个进程接起来 连接
绝对值 |-3| 把数字夹起来 分隔
正则 cat|dog 把选项隔开 分隔
位或 5 | 3 把两股二进制合并 连接
表格 把列分开画成格子 分隔

它同时当着连接符和分隔符——而且这两件事是同一件事。

国界线把两个国家分开,但也正是这条线,定义了两边各自的存在。没有边界,就没有「这边」和「那边」。管道的竖线把 A 的输出接进 B 的输入,但同时也把 A 和 B 保持为两个独立的进程——**正因为它们被隔开,它们才能被连接。**绝对值把「内部」从「外部」隔开,内部才成其为内部。

这就是竖线和其他符号最不一样的地方。& 从「连接」演变成了「分隔」——那是时间线上的漂移。而竖线从一开始就同时是两者:它连接的每一对东西,正因为被它隔开,才各自成立。

顺便说一句中文。汉字里没有竖线语法——方块字不需要一根线来连接或分隔,笔画自己就是边界。所以中文用户第一次认识竖线,几乎都在表格和代码里:它是「竖线」(以形命名)、是「管道符」(以用命名)、是「杠」(随手叫的)。英文则干脆叫它 pipe——以用命名,命名里就带着它最著名的那份工。中文看它的形状,英文看它的用处。一个字符的两种命名哲学,本身就是一场连接与分隔。

边界:被隔开,才能被连接

我把 8160 个竖线,按工种分了一次类

代码即证据。我扫了本站的源码目录(420 个 .vue/.ts/.js/.py/.css 文件),数了数竖线的工龄:

竖线的五种工种

  • 单竖线 | 出现 8160 次
  • 双竖线 ||(逻辑或)出现 1802 次
  • 平均每个文件 19.4 个竖线

这 8160 个竖线里,有管道、有正则、有位或、有类型联合、有默认参数——我在自己的代码库里,替它按工种分了一次类。

再顺手验证一遍核心机制:

echo 'hello' | wc -c    # 6 —— 管道连接
python3 -c "print(5 | 3)"   # 7 —— 位或合流
python3 -c "print(abs(-3))"  # 3 —— 绝对值分隔
python3 -c "import re; print(re.findall(r'cat|dog', 'a cat and a dog'))"  # ['cat', 'dog'] —— 正则分隔

四条命令,四种语义,全部零歧义。竖线没有因为身兼数职而精神分裂——它只是把「边界」这件事做到了极致。

ASCII 0x7C,键盘上 Shift+\ 按出来的那根线。字母表收工后剩下的边角料,如今是 Unix 世界观的语法标记、数学的距离符号、正则的选项分隔符、表格的格子线。

符号换工作系列写到这儿,六位主角全数登场:# 被五十个行业征用,~ 从数学漂到撒娇,@ 从羊价变成身份,& 从连词变成分隔,% 同时打着四份工,| 一边连接一切,一边分隔一切。

它们都不是被设计出来的。它们只是恰好在那里,等着被需要。而需要它们的世界,从来没有问过它们原本叫什么。

一根线画下去,两边各有一个世界。它们能各自成立,恰恰是因为这根线。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论