- 当通过管道
tee
将其标准输出发送到 no-op (:
) 命令时,不会打印任何内容并且文件大小为零。 - 当通过管道
tee
将其标准输出发送到 acat
时,所有内容都会正确打印并且文件大小大于零。
这是一个显示它的代码示例(以脚本的第一个输入参数为条件):
#!/usr/bin/env bash
log_filepath="./log.txt"
[ -f "$log_filepath" ] && { rm "$log_filepath" || exit 1 ; }
fail_tee="$1"
while IFS= read -r -d $'\n' line ; do
printf "%s%s\n" "prefix: " "$line" | \
tee -a "$log_filepath" | \
{
if [ -n "$fail_tee" ]; then
# Nothing is printed to stdout/terminal
# $log_filepath size is ZERO.
: # do nothing.
else
# Each line in the input is prefixed w/ "prefix: " and sent to stdout
# $log_filepath size is 46 bytes
cat
fi
}
done <<'EOF'
1
23
456
7890
EOF
不胜感激背后的解释。
我对 no-op:
命令的期望是它不应该阻止tee
将输出发送到文件。
:
in仍然是一个进程,tee ... | :
它持有由 shell 设置的管道的读取端,其另一端正在tee
写入。只是:
立即退出,这会阻止它从管道中读取。(为了使管道的同时动作起作用,shell 必须为管道的每个部分生成一个新进程,即使它只是处理 no-op:
。在您的示例中,该进程将运行if
最后一个语句管道的一部分,然后在“运行”:
内置程序后最终退出。)通常的行为是,当管道的读取器退出(读取端文件描述符关闭)时,写入器在下一次写入时收到 SIGPIPE 信号,这会导致它退出。
这通常是您想要的,因为这意味着如果管道的右侧退出,左侧也会退出,并且不会无用地继续执行可能很长的任务。或者(更糟糕的是)无助地试图写入一个不承认任何写入的阻塞管道,因为数据无处可去。
因为,POSIX 规范
tee
中似乎没有任何例外;最接近的部分是提到文件操作数的写入错误:如果忽略 SIGPIPE,我测试的实现将继续通过调用
EPIPE
返回的错误。write()
GNU coreutils 版本
tee
具有-p
和--output-error
选项来控制写入失败时的操作:虽然它退出的方式是通过 SIGPIPE,但从
tee
忽略信号开始,它不会退出。并且默认使用
-p
的是warn-nopipe
模式,它被描述为“诊断写入任何输出而不是管道的错误”,而不是使其退出的其他选项。在后台,它也会忽略 SIGPIPE 信号,然后停止尝试写入管道。因此,至少使用 GNU 版本,您可以使用
tee -p ... | ...
它来防止它在管道阅读器退出时退出。或者,您可以将右侧程序安排为模仿黑洞的东西,例如cat > /dev/null
(它仍然读取和写入它所获得的所有内容,但内核最终会忽略写入的数据/dev/null
)。这
:
不是一个 nop 过程。它不是cat
没有论据。不读取标准输入,并传递给标准输出(因为这不是 nop。我看到它可以被认为是 nop 管道阶段,但这是另一个想法)。这不是一个过程。您正试图一无所获。我不知道外壳的作用,但如果管道没有连接到任何东西,我不会感到惊讶。(或者可能附加到外壳上,并被忽略)。无论如何,我不希望有什么好事发生。
正如@Kusalananda 所说。管道将等待其输出的进程读取[或至少关闭管道],但没有进程读取或关闭管道。您可以通过管道传输到
cat >/dev/null
[(多态)。或者,如果您可以重定向> /dev/null
(静态)]。其中之一(如果可能,最好不要猫)
另一种多态解决方案(避免给多余的猫添加面包屑):
由于
:
从不从标准输入读取,它会导致 PIPE 信号。收到 PIPE 信号后, tee (默认)退出。使用 a:
将停止一切。--output-error=warn
如果使用 GNU tee(我假设您使用 bash)(不是 tee POSIX 选项),您可以通过添加到 tee 来看到这一点。您可以使用以下方法进行测试:
更改
:
为cat >/dev/null
将避免导致tee
退出的 PIPE。但是:为什么使用 shell 循环处理文本被认为是不好的做法?
逐行读取文本文件(此处为此处的文档)然后将其发送到管道并不是最好的选择。
考虑:
您还可以根据变量的值在数组中设置 tee 选项。
并将输出设置为变量而不是 here-doc: