3

我正在尝试从执行工具的 bash 函数中保存一些日志(其中一些在子 shell 中运行)。此外,我想将所有错误打印到终端。

我的代码在点击 ctr-c 和一个奇怪的日志文件时会导致一个 sigpipe 和退出代码 141。管道失败似乎是由陷阱内的 stdout 重定向到 stderr 引起的,这会破坏 tee 命令的 stdout 流。有趣的是,代码按预期终止,退出代码 130 没有在陷阱或cat命令中使用重定向。

  1. 我仍然无法修复和解释生成的日志文件。为什么有两次回声,为什么陷阱回声也写入文件?

  2. 为什么函数内的重定向不是更早引起的信号管道?

trap '
echo trap_stdout
echo trap_stderr >&2
' INT

fun(){
    echo fun_stdout
    echo fun_stderr >&2
    ( sleep 10 | cat )
}

echo > log
fun >> log 2> >(tee -a log)

日志文件

fun_stdout
fun_stderr
fun_stderr
trap_stdout

编辑:根据oguz ismail回答的工作示例

exec 3>> log
exec 4> >(tee -ai log >&2)
fun 2>&4 >&3
exec 3>&-
exec 4>&-
4

2 回答 2

2

SIGPIPE 的来源是 SIGINT(由 ctrl/c 启动)被发送到所有正在运行的进程:“主”bash 进程(执行 'fun' 函数)和执行 'tee -a' 的子 shell . 结果,在 Ctrl/C 上,两者都被杀死。当主进程尝试向“tee”进程发送“trap_stderr”时,它会得到 SIGPIPE,因为“tee”已经死了。

鉴于 'tee -a' 的作用,保护它免受 SIGINT 的影响是有意义的,并允许它运行直到 'fun' 完成(或被杀死)。考虑对最后一行的以下更改

fun >> log 2> >(trap '' INT ; tee -a log >&2)

这将产生日志文件:

Console (stderr)
fun_stderr
^Ctrap_stderr

Log File: (no duplicates)

fun_stdout
fun_stderr
trap_stdout
trap_stderr

以上还将解决第二个问题,即关于日志文件中的重复行。这是使用 tee 将每个标准错误行发送到日志文件和标准输出的结果。鉴于 stdout 刚刚(通过'>>log')重定向到'log'文件,输出的两个副本都发送到日志文件,而没有发送到终端

鉴于重定向是按顺序执行的,更改“tee”行以将输出发送到原始标准错误(而不是已经重定向的标准输出)将在终端上显示输出(或任何标准错误)

于 2020-07-22T04:06:28.877 回答
2

为什么有两次回声

fun的 stdoutlog在其 stderr 重定向到为 . 创建的 FIFO 之前被重定向到tee,因此tee继承了一个重定向到log. 我可以这样证明:

$ : > file 2> >(date)
$ cat file
Sat Jul 25 18:46:31 +03 2020

更改重定向的顺序将解决此问题。例如:

fun 2> >(tee -a log) >> log

为什么陷阱回声也写入文件?

如果为 SIGINT 设置的陷阱在 shell 仍在执行时被触发,则fun与之相关的重定向fun生效是完全正常的。

要将陷阱操作的 stdout 和 stderr 连接到主 shell 的 stdout 和 stderr,您可以执行以下操作:

exec 3>&1 4>&2

handler() {
  : # handle SIGINT here
} 1>&3 2>&4

trap handler INT

或类似的东西;这个想法是复制主外壳的标准输出和标准错误。

为什么函数内的重定向不是更早引起的信号管道?

因为在被执行tee时还活着。echo fun_stderr >&2并且sleep不向其标准输出写入任何内容,因此它不能触发 SIGPIPE。

该脚本因 SIGPIPE 而终止的原因是它也tee接收键盘生成的 SIGINT,并在执行与 SIGINT 关联的陷阱操作之前终止。结果,在执行时echo trap_stderr >&2,由于它的 stderr 连接到一个刚刚关闭的管道,shell 接收到 SIGPIPE。

如前所述,为避免这种情况,您可以tee忽略 SIGINT。不过,您不需要为此设置一个空陷阱,该-i选项就足够了。

fun 2> >(tee -a -i log) >> log
于 2020-07-22T06:06:53.960 回答