Bash 由于文件描述符和进程替换而导致的SIGPIPE
我试图保存bash函数中的一些日志,这些函数执行工具(其中一些在子shell中运行)。此外,我想将所有错误打印到终端 在点击ctr-c和一个奇怪的日志文件时,我的代码会导致一个SIGPPIPE和退出代码141。管道故障似乎是由陷阱内的stdout重定向到stderr引起的,这会中断tee命令的stdout流。有趣的是,代码按预期终止,退出代码为130,没有陷阱中使用的重定向或Bash 由于文件描述符和进程替换而导致的SIGPIPE,bash,file-descriptor,bash-trap,process-substitution,Bash,File Descriptor,Bash Trap,Process Substitution,我试图保存bash函数中的一些日志,这些函数执行工具(其中一些在子shell中运行)。此外,我想将所有错误打印到终端 在点击ctr-c和一个奇怪的日志文件时,我的代码会导致一个SIGPPIPE和退出代码141。管道故障似乎是由陷阱内的stdout重定向到stderr引起的,这会中断tee命令的stdout流。有趣的是,代码按预期终止,退出代码为130,没有陷阱中使用的重定向或cat命令 我仍然无法修复和解释生成的日志文件。为什么会有两次回音,为什么陷阱回音也会写入文件 为什么sigpipe不是
cat
命令
fun\u stdout
乐趣
乐趣
陷阱
编辑:根据oguz ismail的工作示例回答
exec 3>> log
exec 4> >(tee -ai log >&2)
fun 2>&4 >&3
exec 3>&-
exec 4>&-
SIGPIPE的来源是SIGINT(由ctrl/c启动)被发送到所有正在运行的进程:“main”bash进程(执行“fun”函数)和执行“tee-a”的子shell。结果,在Ctrl/C上,两个都会被杀死。当主进程尝试将“trap_stderr”发送到te“tee”进程时,它会得到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将每个stderr行发送到日志文件和stdout的结果。假设stdout刚刚被重定向(通过'>>log')到'log'文件,那么输出的两个副本都被发送到日志文件,没有一个发送到终端
如果按顺序执行重定向,则更改“T”行以将输出发送到原始stderr(而不是已重定向的stdout)将在终端上显示输出(或任何stderr)
为什么会有两次回声
fun
的stdout在其stderr重定向到为tee
创建的FIFO之前被重定向到log
,因此tee
继承重定向到log
的stdout。我可以这样证明:
$:>文件2>>(日期)
$cat文件
星期六2020年7月25日18:46:31+03
改变重定向的顺序可以解决这个问题。例如:
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
或者类似的东西;这个想法是复制主shell的stdout和stderr
为什么sigpipe不是由函数内的重定向引起的
因为tee
在执行echo-fun\u-stderr>&2
时处于活动状态。而且sleep
不会向其标准输出写入任何内容,因此它无法触发SIGPIPE
此脚本由于SIGPIPE而终止的原因是tee
也接收由键盘生成的SIGINT,并在执行与SIGINT关联的陷阱操作之前终止。因此,在执行echo trap\u stderr>&2
时,由于其stderr连接到一个刚才已关闭的管道,因此外壳接收到SIGPIPE
为了避免这种情况,如前所述,您可以使tee
ignoresigint。不过,您不需要为此设置空陷阱,-i
选项就足够了
fun 2> >(tee -a -i log) >> log
fun 2> >(tee -a -i log) >> log