命令输出管道至':'命令的陌生脚本模式:用途咨询
command | :这种写法的实用场景 这问题提得太对了!我维护老脚本的时候也碰过好几次这种看起来莫名其妙的写法,一开始以为是手滑写错了,后来查资料、问老运维才搞懂它的几个正经用途——除了你提到的fork bomb(那其实是借了:命令的短名字搞的恶作剧,和空命令本身的功能没关系),还有这些实际场景:
1. 快速终止狂输出的命令
:命令根本不会读标准输入,所以当你把一个不停吐输出的命令通过管道连到它时,管道会立刻被关掉,前面的命令会收到SIGPIPE信号直接终止——这可比command >/dev/null高效多了,后者会让命令把所有输出都写完(哪怕直接丢去/dev/null),而前者直接叫停。
比如你想测试某个命令的启动流程,但不想让它一直输出:
# yes会瞬间终止,而不是无限打印y yes | :
对比yes >/dev/null,后者会一直跑直到你手动kill,而前者秒停。
2. 兼容老旧环境的“丢输出”方案
在一些超老的UNIX系统(或者某些受限的嵌入式环境)里,可能存在/dev/null不可用的情况(比如只读文件系统、早期没有/dev/null的系统),这时候command | :就成了command >/dev/null的替代品——虽然会触发SIGPIPE,但确实能达到不保留输出的效果。
不过现在这种场景已经很少见了,毕竟/dev/null是现代系统的标配。
3. 强制命令在子shell里执行
bash里管道两边的命令默认都会在子shell中运行。有些命令(比如cd、export)在子shell里执行不会影响当前shell的环境,如果你故意想让命令在子shell跑(比如不想改变当前工作目录),又不想处理输出,就可能会用这种写法:
# 切换到/tmp目录执行ls,但当前shell的工作目录不变,同时忽略输出 cd /tmp && ls | :
不过现在更常用的是子shell括号写法:(cd /tmp && ls) >/dev/null,但老脚本可能还沿用| :的写法。
4. 脚本里的临时占位符
有时候写脚本的时候,暂时不想处理某个命令的输出,就会用| :当占位符,后面再改成实际的处理逻辑(比如| grep error或者| tee run.log)。这种属于临时写法,但偶尔会被留在老脚本里没改。
补充::命令到底是什么
:是bash的内置空命令,等价于true,但字符更短。它唯一的作用就是返回退出码0,啥实际操作都不做,也不读标准输入。这就是为啥管道到它会触发SIGPIPE——前面的命令还在往管道写数据,结果另一端已经关了。
如果你拿不准这个写法是不是笔误,可以看看脚本的注释和上下文:如果注释说要“丢弃输出”或者“快速终止命令”,那大概率是有意为之;如果逻辑上应该处理输出却写了| :,那可能是手滑写错了(比如本来想写| grep :或者| sort之类的)。
内容的提问来源于stack exchange,提问作者aka

