通过 tee 将标准输出重定向到文件时隐藏的信号处理程序中的日志



我有一个这样的python程序:

import signal, time
def cleanup(*_):
    print("cleanup")
    # do stuff ...
    exit(1)
# trap ctrl+c and hide the traceback message
signal.signal(signal.SIGINT, cleanup)
time.sleep(20)

我通过脚本运行程序:

#!/bin/bash
ARG1="$1"
trap cleanup INT TERM EXIT
cleanup() {
    echo "ncleaning up..."
    killall -9 python >/dev/null 2>&1
    killall -9 python3 >/dev/null 2>&1
    # some more killing here ...
}
mystart() {
    echo "starting..."
    export PYTHONPATH=$(pwd)
    python3 -u myfolder/myfile.py $ARG1 2>&1 | tee "myfolder/log.txt"
}
mystart &&
cleanup

我的问题是消息清理没有出现在终端上,也没有出现在日志文件中。

但是,如果我调用程序而不重定向输出,它可以正常工作。

如果您不希望发生这种情况,请将tee放在后台,这样它就不会成为进程组的一部分,以便它不会成为获取SIGINT的过程组的一部分。例如,对于 bash 4.1 或更高版本,您可以使用提供句柄的自动分配的文件描述符启动进程替换:

#!/usr/bin/env bash
#              ^^^^ NOT /bin/sh; >(...) is a bashism, likewise automatic FD allocation.
exec {log_fd}> >(exec tee log.txt)  # run this first as a separate command
python3 -u myfile >&"$log_fd" 2>&1  # then here, ctrl+c will only impact Python...
exec {log_fd}>&-                    # here we close the file & thus the copy of tee.

当然,如果将这三个命令放在一个脚本,则整个脚本将成为您的前台进程,因此需要不同的技术。因此:

python3 -u myfile > >(trap '' INT; exec tee log.txt) 2>&1

^C 会将SIGINT发送到整个前台进程(当前管道或 shell"作业"(,在它可以将处理程序的输出写入任何位置之前杀死tee。 您可以使用 shell 中的trap来免疫命令SIGINT ,尽管这会带来明显的风险。

只需使用 tee-i--ignore-interrupts 选项。文档 说:

-i, --ignore-interrupts
    ignore interrupt signals

https://helpmanual.io/man1/tee/

最新更新