使用system(3)运行bash脚本未收到信号

Zax*_*ter 5 bash

我有一个bash脚本,在发出守护进程信号之前等待3分钟.在这3分钟内,如果收到它,我需要它退出SIGINT.

我当前的脚本在从bash运行时工作,但是,当我使用该system()调用从另一个(C)程序中运行它exit时,它在发送时不会SIGINT.

这是我当前的脚本:

#!/bin/bash

trap 'exit' INT
sleep 180 &
wait
trap '' INT

/etc/init.d/myd sync
Run Code Online (Sandbox Code Playgroud)

这是我运行它的方式:

kill -INT `pgrep myscript.sh` 2>/dev/null; ! pgrep -x "myscript.sh" > /dev/null && /opt/my/scripts/myscript.sh &
Run Code Online (Sandbox Code Playgroud)

使用system()呼叫运行时,同一个班轮不起作用.

PS:基本上,/etc/init.d/myd sync如果在3分钟内多次调用它,我只在最后一次调用它之后运行该命令.

编辑1

要求的C代码:

system("kill -INT `pgrep myscript.sh` 2>/dev/null; ! pgrep -x \"myscript.sh\" > /dev/null && /opt/my/scripts/myscript.sh &");
Run Code Online (Sandbox Code Playgroud)

C程序非常庞大(跨越数十个文件),所以我只是在这里粘贴特定的调用.该程序应该作为守护进程运行,但即使我不将其作为守护进程运行(使用命令行开关),我也会遇到此问题.

我可以使用以下简单的C代码重现这一点:

#include <stdlib.h>

int main(int argc, char *argv[]) {
    system("kill -INT `pgrep myscript.sh` 2>/dev/null; ! pgrep -x \"myscript.sh\" > /dev/null && /opt/my/scripts/myscript.sh &");        
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

hme*_*ia1 1

原因(更新):

  • 实际的进程名称是bash,而不是myscript.sh
  • pgrep 可以通过sh调用system()来匹配自身
  • 当脚本在后台运行时, SIGINT 的表现并不好。(已使用 SIGUSR1 代替)

经过对各种操作系统的一些讨论和测试,一旦消除了微妙之处,这实际上可以归结为:

  1. 从 tty 启动脚本时,ps将显示以下内容:
46694 s001  S+     0:00.01 /bin/bash /opt/my/scripts/myscript.sh
Run Code Online (Sandbox Code Playgroud)
  1. system()从调用(通过sh)启动脚本时,ps将显示以下内容:
46796 s002  S      0:00.00 /bin/bash /opt/my/scripts/myscript.sh
Run Code Online (Sandbox Code Playgroud)

ps手册中:

    • state   第一个字符表示进程的运行状态:
      
          S   标记睡眠时间少于 20 秒的进程
      这些后面的附加字符(如果有), 指示附加状态信息:

      + 该进程位于其控制终端的前台进程组中。

所以没有+ 的进程不会使用 SIGINT。

事实证明我们可以捕获SIGUSR1并将其发送kill -USR1


Ubuntu 16.04 和 Mac OS X 10.12 上的工作测试:

cmon.c

  • #include 
    int main(int argc, char *argv[]) {
    system("mypid=`cat /opt/my/scripts/myscript.pid` ; ps -p $mypid > /dev/null && kill -USR1 $mypid 2>/dev/null ; mypid=`cat /opt/my/scripts/myscript.pid` ; ps -p $mypid > /dev/null || /opt/my/scripts/myscript.sh &");
    return 0;
    }
    
    Run Code Online (Sandbox Code Playgroud)

/opt/my/scripts/myscript.sh

  • #!/bin/bash
    #process for this instance of bash bashpid="$$"

    #ensure single instance mypid="$(cat "$(dirname "$0")/myscript.pid" 2>/dev/null)" ps -p $mypid &> /dev/null && (echo "already running, now going to exit this instance" ; echo "seems we never see this message, that's good, means the system() call is only spawning a new instance if there's no process match." ; kill -9 "$bashpid")

    #set pidfile for this instance echo "$bashpid" > "$(dirname "$0")/myscript.pid"
    trap 'echo "BYE" ; exit' SIGUSR1 sleep 5 & # 30 seconds for testing wait trap '' SIGUSR1
    echo "Sitting here in limbo land" & while true ; do sleep 5 ; done
    Run Code Online (Sandbox Code Playgroud)

测试

./cmon循环二进制文件并检查每次是否得到不同的进程(在超时窗口内)的简单行:

unset i ; until [[ i -eq 5 ]] ; do ./cmon ; ps ax | grep bash.*myscript.sh | grep -v grep | awk -F ' ' '{print $1 " " $6}' ; sleep 1 ; (( i ++ )) ; done
Run Code Online (Sandbox Code Playgroud)

一旦超时到期,可以运行同一行,以检查所有进程号是否相同

可以在此处找到可粘贴的完整单元测试构建和测试序列: ybin 链接

它的演示在这里运行:

在此输入图像描述

有关过程的注意事项

  • 修改脚本只是为了便于测试(即 10 秒超时窗口)。
  • 冗余添加单实例检查(myscript.sh 文件中的单实例触发器永远不应该被触发......并且似乎永远不会被触发)

OP 确认最终工作后进行更新