【问题标题】:Why does "tee /tmp/my.log | my-binary" not exit immediately when my-binary is killed?为什么 my-binary 被杀死时“tee /tmp/my.log | my-binary”不会立即退出?
【发布时间】:2017-11-04 23:55:45
【问题描述】:

我有以下脚本:

我的脚本.sh

#!/bin/bash
set -e
set -o pipefail
tee /tmp/my.log | my-binary

...运行时如下:

$ cat my-data.txt | my-script.sh

我假设当我的二进制文件崩溃或被杀死时,脚本tee 的副本应该立即退出。然而,当 shell 本身退出时,tee 不会。

【问题讨论】:

  • 这还不足以让其他人重现该问题。 “杀死它”带有哪个特定信号?如果my-binary 选择以退出以外的方式处理信号,则信号可能会被捕获。
  • (顺便说一句,pipefail 将确保退出状态指示失败,如果 tee 失败但 my-binary 成功退出,但如果它是my-binary 失败,pipefail 没有任何效果)。
  • ...set -e 也无关紧要,尽管在大多数情况下它是portability issuesgeneral nonintuitiveness 的来源(如果赶时间,请跳过寓言并查看练习)。
  • 我使用“kill -9”并且发现 my-script.sh 进程被杀死。但是 tee 过程仍然存在。
  • 谢谢——这有助于澄清问题。

标签: bash pipe tee


【解决方案1】:

The POSIX specification for tee 指定如果写入命名操作数(例如/tmp/my.log)失败,tee 命令需要继续写入其他输出。

为了满足这个规范,tee 的常见实现——包括 GNU 实现和 Busybox one——完全忽略了 SIGPIPE。即使/tmp/my.log 是提前关闭的命名管道,这也允许它们继续操作。

作为 SIGPIPE 信号的副作用——在 FIFO 的另一端中止时收到——被忽略,tee 不会立即注意到它的输出到my-binary 的标准输入关闭时,而只是稍后会在尝试写入失败时通知。


如果立即杀死 tee 很重要,并且您正在运行 bash 4.4 或更高版本,我建议改为以下实现:

#!/usr/bin/env bash

# replace stdin with a pipe from tee
exec < <(tee /tmp/my.log)

# collect PID for the process substitution; REQUIRES BASH 4.4 OR NEWER
tee_pid=$!
trap 'kill "$tee_pid"' EXIT

my-binary

【讨论】:

    猜你喜欢
    • 2016-06-04
    • 2021-06-07
    • 2020-09-11
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多