为什么 SIGSTOP 在屏幕会话内不起作用?

为什么 SIGSTOP 在屏幕会话内不起作用?

考虑以下脚本:

#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP $$
echo 'after stop' > ${OFILE}

在交互式 shell 中,脚本停止并且输出为ok.但是,如果它启动为

screen -d -m ./test.sh

输出是after stop.屏幕处理信号吗?如何在屏幕会话中暂停进程?

答案1

也许 screen 进程正在重新启动停止的 bash 进程。我尝试了以下操作(向两个进程发送 SIGSTOP 信号):

测试文件

#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
echo 'screen pid ' $(screen -list | grep sc_test | cut -f1 -d'.' | sed 's/\W//g') >> ${OFILE}
echo 'test.sh pid ' $$ >> ${OFILE}
kill -SIGSTOP $(screen -list | grep sc_test | cut -f1 -d'.' | sed 's/\W//g')
kill -SIGSTOP $$
echo 'after stop' >> ${OFILE}

屏幕命令

screen -dmS sc_test ./test.sh

日志档案

ok
screen pid  4453
test.sh pid  4454

列表屏幕

screen -list
There is a screen on:
        4453.sc_test    (11/05/2015 10:45:20 AM)        (Detached)
1 Socket in /var/run/screen/S-root.

答案2

的检查GNU screen-4.0.2 源代码显示 screen 检查其子进程是否停止,然后尝试使用 SIGCONT 恢复它们。这是相关部分screen.c

1561 if (WIFSTOPPED(wstat))
1562   {   
1563     debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
....
1578     /* Try to restart process */
1579     Msg(0, "Child has been stopped, restarting.");
1580     if (killpg(p->w_pid, SIGCONT))
1581       kill(p->w_pid, SIGCONT);
1582   }   

似乎无法通过选项或配置文件更改此行为。建议的停止屏幕处理的解决方案可能会产生不良的副作用。更好的方法是从屏幕上隐藏停止的进程。对于 bash 脚本,可以使用子 shell 来完成:

#!/bin/bash
(   
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP ${BASHPID}
echo 'after stop' > ${OFILE}
)   

对于其他 shell 可能不那么简单,例如对于 tcsh:

#!/bin/tcsh
(\  
set OFILE='log' ;\
echo 'ok' > ${OFILE} ;\
kill -STOP `exec sh -c 'echo ${PPID}'` ;\
echo 'after stop' > ${OFILE} \
)   

主要区别在于获取子shell PID的方法,更多信息这里

或者,可以在不修改的情况下启动脚本包装纸脚本:

#!/bin/bash
SCRIPTDIR="$(dirname "$(readlink -f -n "$0")")"
${SCRIPTDIR}/test.sh

跑步:

screen -d -m ./wrapper.sh

相关内容