AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 720235
Accepted
Dor
Dor
Asked: 2022-10-09 01:02:54 +0800 CST2022-10-09 01:02:54 +0800 CST 2022-10-09 01:02:54 +0800 CST

Bash:“tee”被下一个管道中的“no-op”阻止

  • 772
  • 当通过管道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将输出发送到文件。

bash pipe
  • 3 3 个回答
  • 379 Views

3 个回答

  • Voted
  1. Best Answer
    ilkkachu
    2022-10-09T02:10:33+08:002022-10-09T02:10:33+08:00

    :in仍然是一个进程,tee ... | :它持有由 shell 设置的管道的读取端,其另一端正在tee写入。只是:立即退出,这会阻止它从管道中读取。(为了使管道的同时动作起作用,shell 必须为管道的每个部分生成一个新进程,即使它只是处理 no-op :。在您的示例中,该进程将运行if最后一个语句管道的一部分,然后在“运行”:内置程序后最终退出。)

    通常的行为是,当管道的读取器退出(读取端文件描述符关闭)时,写入器在下一次写入时收到 SIGPIPE 信号,这会导致它退出。

    这通常是您想要的,因为这意味着如果管道的右侧退出,左侧也会退出,并且不会无用地继续执行可能很长的任务。或者(更糟糕的是)无助地试图写入一个不承认任何写入的阻塞管道,因为数据无处可去。

    因为,POSIX 规范tee中似乎没有任何例外;最接近的部分是提到文件操作数的写入错误:

    如果写入任何成功打开的文件操作数失败,则写入其他成功打开的文件操作数和标准输出应继续,但退出状态应为非零。

    如果忽略 SIGPIPE,我测试的实现将继续通过调用EPIPE返回的错误。write()

    GNU coreutils 版本tee具有-p和--output-error选项来控制写入失败时的操作:

    未指定时的默认操作--output-error是在写入管道出错时立即退出,并诊断写入非管道输出的错误。

    虽然它退出的方式是通过 SIGPIPE,但从tee忽略信号开始,它不会退出。

    并且默认使用-p的是warn-nopipe模式,它被描述为“诊断写入任何输出而不是管道的错误”,而不是使其退出的其他选项。在后台,它也会忽略 SIGPIPE 信号,然后停止尝试写入管道。

    因此,至少使用 GNU 版本,您可以使用tee -p ... | ...它来防止它在管道阅读器退出时退出。或者,您可以将右侧程序安排为模仿黑洞的东西,例如cat > /dev/null(它仍然读取和写入它所获得的所有内容,但内核最终会忽略写入的数据/dev/null)。

    • 5
  2. ctrl-alt-delor
    2022-10-09T01:18:43+08:002022-10-09T01:18:43+08:00

    这:不是一个 nop 过程。它不是cat没有论据。不读取标准输入,并传递给标准输出(因为这不是 nop。我看到它可以被认为是 nop 管道阶段,但这是另一个想法)。这不是一个过程。

    您正试图一无所获。我不知道外壳的作用,但如果管道没有连接到任何东西,我不会感到惊讶。(或者可能附加到外壳上,并被忽略)。无论如何,我不希望有什么好事发生。

    正如@Kusalananda 所说。管道将等待其输出的进程读取[或至少关闭管道],但没有进程读取或关闭管道。您可以通过管道传输到cat >/dev/null[(多态)。或者,如果您可以重定向 > /dev/null(静态)]。

    其中之一(如果可能,最好不要猫)

    | cat >/dev/null
    >/dev/null
    

    另一种多态解决方案(避免给多余的猫添加面包屑):

    if ...
    then
      out=/dev/stdout
    else
      out=/dev/null
    fi
    
    command >"$out"
    
    • 3
  3. QuartzCristal
    2022-10-09T08:20:38+08:002022-10-09T08:20:38+08:00

    由于:从不从标准输入读取,它会导致 PIPE 信号。收到 PIPE 信号后, tee (默认)退出。使用 a:将停止一切。

    --output-error=warn如果使用 GNU tee(我假设您使用 bash)(不是 tee POSIX 选项),您可以通过添加到 tee 来看到这一点。

    您可以使用以下方法进行测试:

    $ echo "hello" | tee --output-error=warn | :
    tee: 'standard output': Broken pipe
    

    更改:为cat >/dev/null将避免导致tee退出的 PIPE。

    但是:为什么使用 shell 循环处理文本被认为是不好的做法?

    逐行读取文本文件(此处为此处的文档)然后将其发送到管道并不是最好的选择。

    考虑:

    sed 's/^/preffix: /' <<'EOF' | tee -a "$log_filepath"
    1
    23
    456
    7890
    EOF
    

    您还可以根据变量的值在数组中设置 tee 选项。

    并将输出设置为变量而不是 here-doc:

    #!/bin/bash --
    
    log_filepath="./log.txt"
    [ -f "$log_filepath" ] && { rm "$log_filepath" || exit 1 ; }
    
    enable_stdout="${1:+"yes"}"
    enable_log="yes" # comment this line to avoid logging.
    
    out=$'1\n23\n456\n7890\n'
    
    unset teeoptions; teeoptions=()
    [ -n "$enable_stdout" ] && teeoptions+=(-a "/dev/tty")
    [ -n "$enable_log" ]    && teeoptions+=(-a "$log_filepath")
    
    printf '%s' "$out" | 
        sed 's/^/preffix: /' | 
        tee "${teeoptions[@]}" >/dev/null
    
    • 3

相关问题

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve