防止SIGINT关闭bash脚本中的子进程 [英] Prevent SIGINT from closing child process in bash script

查看:115
本文介绍了防止SIGINT关闭bash脚本中的子进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个bash脚本,其中编写了一个处理程序来照顾用户何时按下Control + C(通过使用trap interruptHandler SIGINT),但SIGINT既发送到bash脚本又发送到子进程,即当前正在运行,正在关闭子进程.如何防止这种情况发生?

I am writing a bash script in which I wrote a handler to take care of when the user pressed Control+C, (by using trap interruptHandler SIGINT) but the SIGINT gets sent to both the bash script and the child process that is currently running, closing the child process. How can I prevent this from happening?

这是脚本,不要过多批评我的技能.

edit: here's the script, don't critique my skills too much..

#!/bin/bash
trap "interruptHandler" SIGINT

inInterrupt=false;
quit=false;

if [ -z ${cachedir+x} ]; then cachedir=~/.cache/zlima12.encoding; fi
cachedir=$(realpath ${cachedir});


if [ ! -e ${cachedir} ]; then mkdir ${cachedir}; fi
if [ ! -e ${cachedir}/out ]; then mkdir ${cachedir}/out; fi

cleanCache ()
{
    rm ${cachedir}/*.mkv;
    rm ${cachedir}/out/*.mkv;
}

interruptHandler ()
{
    if [ ${inInterrupt} != true ]; then
        printf "BASHPID: ${BASHPID}";
        inInterrupt=true;
        ffmpegPID=$(pgrep -P ${BASHPID});
        kill -s SIGTSTP ${ffmpegPID};
        printf "\nWould you like to quit now(1) or allow the current file to be encoded(2)? ";
        read response;
        if [ ${response} = "1" ]; then kill ${ffmpegPID}; cleanCache;
        elif [ ${response} = "2" ]; then quit=true; kill -s SIGCONT ${ffmpegPID};
        else printf "I'm not sure what you said... continuing execution.\n"; kill -s SIGCONT ${ffmpegPID};
        fi

        inInterrupt=false;
    fi
}



for param in "$@"; do

    dir=$(realpath ${param});

    if [ ! -e ${dir} ]; then
        printf "Directory ${dir} doesn't seem to exist... Exiting...\n"
        exit 1;
    elif [ -e ${dir}/new ]; then
        printf "${dir}/new already exists! Proceed? (y/n) ";
        read response;
        if [ ${response} != y ]; then exit 1; fi
    else
        mkdir ${dir}/new;
    fi

    for file in ${dir}/*.mkv; do
        filename="$(basename ${file})";
        cp $file ${cachedir}/${filename};
        ffmpeg -vsync passthrough -i ${cachedir}/${filename} -c:v libx265 -c:a copy -f matroska ${cachedir}/out/${filename};
        rm ${cachedir}/${filename};
        mv ${cachedir}/out/${filename} ${dir}/new/${filename};

        if [ ${quit} = true ]; then exit 0; fi
    done
done

(这是一个脚本,用于在您好奇的情况下将matroska(mkv)文件编码为H.265)

(This is a script to encode matroska (mkv) files to H.265 in case you're curious)

推荐答案

在此处执行了一个简单的测试,并提供了预期的结果:

Performed a simple test here and it delivers the expected result:

int.sh内容:

#!/bin/bash

trap '' SIGINT
tail -f /var/log/syslog >& /dev/null

测试:

$ ./int.sh
^C^C
# ... SIGINT ignored (CTRL+C) ...
# ... Will send SIGTSTP with CTRL+Z ...
^Z
[1]+  Stopped                 ./int.sh
$ kill %1
$
[1]+  Terminated              ./int.sh
$

编辑(回答问题):

您可能希望捕获并忽略其他命令(例如脚本中的(trap '' SIGINT && command))的SIGINT,因此可以防止在调用interruptHandler之前从当前命令捕获信号.

You probably want to trap and ignore SIGINT for every other command, such as (trap '' SIGINT && command) in your script, so you can prevent the signal being caught from the current command before interruptHandler is invoked.

一个简单的例子:

#!/bin/bash

function intHandler() {
        echo "If SIGINT was caught, this will be printed AFTER sleep exits."
}

trap intHandler SIGINT

sleep 5 # Sleep will exit as soon as SIGINT is caught

输出:

$ time ./int.sh 
^C
# ... Right here, only 0.6 seconds have elapsed before the below message being printed ...
If SIGINT was caught, this will be printed AFTER sleep exits.

real    0m0.634s
user    0m0.004s
sys     0m0.000s

请注意,由于捕获了SIGINT,它只持续了0.6秒.

Note that it only lasted for 0.6 seconds due to SIGINT being caught.

但是当您忽略sleep的SIGINT时:

But when you ignore SIGINT for sleep:

function intHandler() {
        echo "If SIGINT was caught, this will be printed AFTER sleep exits."
}

trap intHandler SIGINT

(trap '' SIGINT && sleep 5)

输出为:

$ time ./int.sh
^C
# ... Right here, 5 seconds have elapsed without any message ...
If SIGINT was caught, this will be printed AFTER sleep exits.

real    0m5.007s
user    0m0.000s
sys     0m0.000s

请注意,尽管SIGINT已被脚本传递并捕获,但intHandler仅在当前sleep退出时返回,并且还请注意,当前sleep并未捕获SIGINT从父级(持续了整整5秒钟)开始,直到它运行所在的子shell(( ... ))忽略了SIGINT.

Note that despite the SIGINT was delivered and caught by the script, the intHandler will only return when the current sleep exits, and also note that the current sleep didn't caught the SIGINT from the parent (it lasted for the full 5 seconds) as the subshell where it's running on (the ( ... )) is ignoring SIGINT.

这篇关于防止SIGINT关闭bash脚本中的子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆