使用管道命令忽略Bash脚本中的HUP信号
我有以下脚本无限期监视/ tmp目录,如果该目录中有文件操作,则while循环读取文件名,首先用b字符替换文件名中的字符,此修改后的文件名为记录到test.log文件:
#!/bin/bash trap ':' HUP trap 'kill $(jobs -p)' EXIT /usr/local/bin/inotifywait -q -m /tmp --format %f | while IFS= read -r filename; do echo "$filename" | sed 's/a/b/' > test.log done 这是实际脚本的简化版本.我上面的脚本也有一个Sys-V类型的init脚本,因为我希望保持LSB兼容,我的init脚本有force-reload(如果服务支持,则重新加载配置.否则,服务重新启动) .)将HUP信号发送到脚本的选项.现在在执行执行killproc -HUP test.sh的force-reload之前,pstree的输出如下: # pstree -Ap 4424 test.sh(4424)-+-inotifywait(4425) `-test.sh(4426) # 执行strace killproc -HUP test.sh后,子shell终止: # pstree -Ap 4424 test.sh(4424)---inotifywait(4425) # 根据strace,killproc将SIGHUP发送到进程4424和4426,但只有后者被终止. 在我的例子中,这个带有PID 4426的子shell有什么意义,即为什么它首先被创建?另外,有没有办法忽略HUP信号?
管道命令在子shell中运行
问题的第一部分是通过shell(在本例中为Bash)在管道中运行命令的机制来解释的. 管道是FIFO(先进先出)单向进程间通信(IPC)通道:它允许在一端(只写端)写入字节,从另一端读取字段(只读端) )无需读取或写入物理文件系统. 管道允许两个不同的命令通过匿名或未命名(即,在文件系统中没有条目)管道彼此通信. 当shell执行简单命令时,该命令在shell的子进程中运行.如果没有使用作业控制,则当子进程终止时,shell将重新获得对终端的控制. 当在管道中运行两个命令时,管道中的两个命令都作为两个单独的子进程执行,这些子进程同时运行. 在Unix系统中,使用pipe(2)系统调用创建管道,该管道创建一个新管道并返回一对文件描述符,其中一个引用读取端,另一个引用管道的写入端. 在GNU / Linux系统上使用Bash时,clone(2)系统调用用于创建子进程.这允许子进程与其父进程共享文件描述符表,以便两个子子进程都继承匿名管道的文件描述符,以便可以读取它并且另一个可以写入它. 在您的情况下,inotifywait命令获得4425的PID,并通过将其stdout连接到写端的文件描述符来写入管道的只写端. 同时,管道命令的右侧获取PID,4426并且其stdin文件描述符设置为管道的只读端的描述符.由于管道右侧的子shell不是外部命令,因此表示子进程的名称与其父进程test.sh的名称相同. 有关更多信息,请参阅man 7 pipe和以下链接: > Anonymous pipe,Wikipedia article 信号处理 我花了很长时间(实际上是几个小时的研究)来弄清楚为什么SIGHUP信号的陷阱没有被忽略. 我的所有研究表明,由clone(2)系统调用创建的子进程也应该能够共享父进程的信号处理程序表. Bash手册页也说明了这一点
它后来说明了这一点
这表明子shell不继承未被忽略的信号处理程序.正如我所理解的那样,你的陷阱’:’HUP行意味着(有效)忽略了SIGHUP信号(因为:builtin除了返回成功之外什么都不做) – 而且应该被管道的子shell忽略. 但是,我最终遇到了Bash手册页中内置陷阱的描述,该手册定义了忽略Bash的含义:
简单地将陷阱命令更改为陷阱”HUP可确保忽略SIGHUP信号,脚本本身以及任何子壳. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |