Bash 中的“:”(冒号)函数在管道中使用时的语义?

Bash 中的“:”(冒号)函数在管道中使用时的语义?

问题

:关于它在管道中的使用,其语义是什么?

bash 文档状态:

: [arguments]
没有效果;该命令除了扩展参数和执行任何指定的重定向之外不执行任何操作。返回状态为零。

:然而,在管道中使用时我应该期望什么行为并不明显。它只是简单地通过吗std{in,out,err}

看来,参数:可以替代任何其他命令。但我需要澄清一下在管道中的使用;澄清不仅基于观察,而且引用权威消息来源

背景

我遇到一种情况,根据脚本运行的环境,我需要运行输出以tr -d '\r'从输出中删除回车符。

唉,目前这意味着一个if/else/fi区块,类似于 (在函数内部):

if [[ "$OSTYPE" == "cygwin" ]]; then
    my_commands | tr -d '\r' || return $?
else
    my_commands || return $?
fi

其中 the是 the和Branch| tr -d '\r'之间的唯一区别。当然,任一分支的内容都比此处显示的要复杂得多。ifelse

现在,我知道tr -d '\r'在没有回车的情况下这是良性的。但这是一个调用和(在 Windows 上)可以避免的开销(该函数是“热”代码路径)。所以我想到tr用内置的shell函数来替换:

答案1

在这种情况下,传递替换是cat,它将其输入复制到其输出。:不执行任何操作,因此您的输入将丢失:

$ echo hello | :
$

事实上,由于:不读取其输入,输入管道的命令将收到一个SIGPIPE,因此它们可能无法完成任务,甚至无法启动它:

$ (seq 1 10000 | tee /dev/stderr; echo $? 1>&2) | :
141

使用cat意味着外部调用,就像tr(但工作量稍少)。 Bash 没有这种类型的内置传递。

答案2

不管名称如何奇怪,:它仍然是一个命令并且行为就像一个命令,因此当它不执行任何操作时,意味着它也不会从管道中读取任何内容。从某种意义上说,它不是 shell 的特殊语法,| : |可以减少回|.POSIX 描述:确实说它不“使用”标准输入或标准输出,但当然它没有明确提到那里的管道。

对此有一些解决方案条件管道cat,但大多数情况下,避免在中间运行副本是很困难或尴尬的。

(细则:POSIX 文本使用术语“实用程序”,但它仍然与用于例如的术语相同ls。此外,:它并不完全是一个常规命令,而是一个“特殊内置”,这在一些较小的方面有所不同案例,但不在这里。)

答案3

手册页中的关键短语是:(就像它的同义词一样true什么也没做。它不会从输入中读取任何内容,也不会将任何内容写入其输出流。

在管道中,它不是很有用——它就像管道中的堵塞物一样。

相关内容