竖线 |:管道、按位或、掩码组合

一、前言

在 Linux 学习过程中,绝大多数人都会被同一个符号 | 搞混淆:

命令行里它是管道、代码里它是位运算、系统函数参数里它是标志叠加。

很多人疑惑:明明都是竖线,为什么功能完全不同?

标准答案:符号本身没有任何意义,解析环境决定意义。

Shell 解释器、C语言编译器、Linux 内核,三套完全不同的解析规则,互不干涉。


二、Shell 终端中:| 是「管道符」

1. 作用

Shell 里的|和数学运算没有任何关系

它的唯一作用:把前一个命令的输出,交给后一个命令当输入,实现进程数据接力。

2. 特点

  • 多个命令同时运行(流水线并发)

  • 数据在内存流动,不产生临时文件

  • 下游依赖上游输出,实现链式数据处理

3. 示例

bash 复制代码
ls -l | grep txt | wc -l
cat app.log | grep error | awk '{print $5}' | sort | uniq -c

4. Shell 极易混淆四组符号

  • | 管道:数据接力

  • || 逻辑或:前命令失败,才执行后命令

  • && 逻辑与:前命令成功,才执行后命令

  • & 后台并行:两个命令独立同时跑


三、编程语言中:| 是「按位或运算符」

在 C / C++ / Python / Java 中,| 是标准 二进制位运算,纯粹数学计算,和管道无关。

1. 运算规则

有1则1,全0才0,逐位独立计算。

cs 复制代码
0b0010 | 0b0100 = 0b0110

2. 基础示例

cs 复制代码
int a = 2;    // 0010
int b = 4;    // 0100
int res = a | b; // 0110 = 6

四、系统编程中:| 是「掩码叠加」(最容易混淆)

你写 open、socket、epoll 时看到的:

O_WRONLY | O_CREAT | O_TRUNC

这里绝对不是管道,是标准按位或运算。

1. 内核 flag 本质

Linux 所有 flag 本质都是 整数掩码

每一个二进制 bit 代表一个开关功能。

内核宏定义简化如下:

cs 复制代码
#define O_WRONLY  0001  // 只写
#define O_CREAT   0100  // 不存在则创建
#define O_TRUNC   1000  // 存在则清空

2. 按位或叠加多个功能

使用 | 可以同时开启多个开关:

cs 复制代码
  0001  O_WRONLY
| 0100  O_CREAT
| 1000  O_TRUNC
= 1101

最终结果同时拥有:只写、创建、清空三种能力。

3. 为什么不能用加号 +

加法会进位、会丢 bit,会导致功能错乱;

按位或只置1、不进位,是唯一安全的叠加方式。

cs 复制代码
#define A 0b0010
#define B 0b0010

A + B = 0b0100  // 错误,进位丢失
A | B = 0b0010  // 正确,保留开关状态

4. 经典系统调用统一写法

cs 复制代码
// 文件打开
open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);

// 非阻塞 socket
socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);

// epoll 多事件监听
ev.events = EPOLLIN | EPOLLOUT;

五、一张表彻底终结混淆

使用场景 符号含义 本质 示例
Shell 命令行 管道符 进程数据流传递 `ls
代码数值运算 按位或 二进制数学运算 `x = a
系统函数 flag 掩码按位或 叠加多个功能开关 `O_WRONLY

六、最终总结

  • 终端里的 |管道,负责命令数据流接力;

  • 代码里的 |按位或,负责二进制运算;

  • open/socket 参数里的 |掩码叠加,用来组合多个系统功能;

  • 永远不要用 + 代替 | 组合系统标志;

  • 符号不决定功能,环境决定一切

相关推荐
techdashen1 小时前
Go Map 详解:键值对实际上是如何存储的
开发语言·后端·golang
程序猿乐锅2 小时前
【计算机组成原理 | 第六章】中央处理器 CPU
java·开发语言
大模型丫丫2 小时前
如何提升单体 Spring Boot 应用的并发数?
java·spring boot·后端
Terra.K2 小时前
ThreadLocal解决一个线程里面跨层传递问题
java·开发语言·后端
泡海椒2 小时前
低代码规则开发:JQuick-Java声明式配置驱动开发落地教程
java·低代码·rxjava
变与不变8063 小时前
引用类型、内存原理与对象
开发语言·前端·javascript
wuyk5553 小时前
从零吃透 MQTT 通信|第 5 章 MQTT 心跳保活机制深度优化,断线检测与智能自动重连
c语言·开发语言·stm32·学习
weixin_440730503 小时前
socket解决多次输入问题-大数据接收问题-模块动态导入
java·开发语言·servlet
用户3126874877203 小时前
ReentrantLock 和 synchronized 到底选哪个?源码级对比与选型
java