为什么在从脚本启动的应用程序中按 Control + C 会破坏脚本?

wil*_*hil 3 bash scripts

直接跳进去:

while true; do
    #---  MENU LOGIC HERE, stick response in $MENUEXIT

    #----Deal with responses here

    if [ $S1 == $MENUEXIT ];
    then
            tail -f /path-to-file
    else
            sleep 2
    fi
done
Run Code Online (Sandbox Code Playgroud)

我尽量保持简单,如果您需要更多,请告诉我。

基本上,我在循环中粘贴菜单,因此,如果用户输入不正确或命令完成,则意味着重新显示菜单。

它工作正常,直到我添加了 tail 命令。

如果我从菜单中选择 tail 选项,则 tail 命令可以正常启动 - 但是,如果我点击Ctrl+ C,我希望 tail 终止并显示菜单,但它同时终止 tail脚本。

我尝试了各种方法,例如继续/陷阱等,但是,我遇到了砖墙,需要一些帮助吗?!

mur*_*uru 7

当您从终端发送类似SIGINT( CtrlC) 或SIGSTOP( CtrlZ)的信号时,该信号将被发送到前台进程组。也就是说,由前台作业(您的脚本)及其在前台(命令)中拥有的任何子进程组成的组。这会导致所有这些进程退出(或通过处理信号来执行它们所做的任何事情)。您可以通过使用以下命令发送信号来测试差异:tailkill

在一个终端中,执行此脚本(我test在以下命令中调用它):

#! /bin/bash

while true
do
    if [[ $1 = a ]]
    then
        yes 
    else
        echo no
        sleep 2
    fi
done
Run Code Online (Sandbox Code Playgroud)

在另一个中,执行这些命令:

pstree -ps $(pgrep -f test)
pkill -f test
pstree -ps $(pgrep -f yes)
Run Code Online (Sandbox Code Playgroud)

命令的输出将是这样的:

init(1)???lightdm(1032)???lightdm(1154)???init(1173)???x-terminal-emul(17009)???bash(24262)???test.sh(24996)???yes(24997)
# No output for pkill
init(1)???lightdm(1032)???lightdm(1154)???init(1173)???yes(24997)
Run Code Online (Sandbox Code Playgroud)

(实际数字和程序可能会有所不同,但第一个 init 将始终具有pid 1。)
如您所见,该yes命令没有被终止,而是init因为其父级被终止而被附加。它仍然y在第一个终端上愉快地打印s 。所以用pkill -f yes. 现在重复实验,只做一处改动。而不是pkill -f test,做:

kill -INT -25165 
# Use the pid of test.sh given in parentheses in the output of pstree 
# instead of 25165
Run Code Online (Sandbox Code Playgroud)

注意领先的-. 在 Linux 中,对于kill命令,-25165是进程组,其领导者为 pid 25165。因此,该命令相当于从终端发送中断。

当然,确切的行为取决于 TTY 的配置、登录 shell 等。这就是我的理解。进一步阅读:


我建议:

  1. 发送tail到后台
  2. 捕获信号
  3. 杀死后台进程。
  4. 移除陷阱

一个例子:

#! /bin/bash

kill_jobs ()
{
    kill %1
}

while true
do
    if [[ $1 = "a" ]]
    then
        trap kill_jobs INT
        tail -f /var/log/syslog &
        wait %%
        shift #You don't need to shift, I just didn't want loop tail on this example
        trap - INT
    else
        echo some output
        sleep 2
    fi
done
Run Code Online (Sandbox Code Playgroud)

这可以变得非常强大,通过使用不同的函数进行陷印,并且每个函数都做自己的清理工作。