Рассмотрим следующий сценарий:
#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP $$
echo 'after stop' > ${OFILE}
В интерактивной оболочке скрипт останавливается и выводится ok
. Однако, если он запущен как
screen -d -m ./test.sh
выход after stop
. Обрабатывает ли screen сигнал? Как приостановить процесс в сеансе screen?
решение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показал, что экран проверяет, остановлены ли его дочерние процессы, а затем пытается возобновить их с помощью 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 это можно сделать с помощью подоболочки:
#!/bin/bash
(
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP ${BASHPID}
echo 'after stop' > ${OFILE}
)
Для других оболочек это может быть не так просто, например для tcsh:
#!/bin/tcsh
(\
set OFILE='log' ;\
echo 'ok' > ${OFILE} ;\
kill -STOP `exec sh -c 'echo ${PPID}'` ;\
echo 'after stop' > ${OFILE} \
)
Ключевое отличие заключается в методе получения PID подоболочки, дополнительная информацияздесь.
В качестве альтернативы скрипт можно запустить без изменений с помощьюоберткасценарий:
#!/bin/bash
SCRIPTDIR="$(dirname "$(readlink -f -n "$0")")"
${SCRIPTDIR}/test.sh
Бежать:
screen -d -m ./wrapper.sh