Considere el siguiente guión:
#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP $$
echo 'after stop' > ${OFILE}
En un shell interactivo, el script se detiene y el resultado es ok
. Sin embargo, si se inicia como
screen -d -m ./test.sh
la salida es after stop
. ¿La pantalla maneja la señal? ¿Cómo suspender un proceso en una sesión de pantalla?
Respuesta1
Probablemente el proceso de pantalla esté reiniciando el proceso bash detenido. Intenté lo siguiente (enviando señal SIGSTOP a ambos procesos):
prueba.sh
#!/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}
comando de pantalla
screen -dmS sc_test ./test.sh
archivo de registro
ok
screen pid 4453
test.sh pid 4454
pantallas de listado
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.
Respuesta2
examen de lacódigo fuente de GNU screen-4.0.2mostró que la pantalla verifica si sus procesos secundarios están detenidos y luego intenta reanudarlos con SIGCONT. He aquí una parte relevante de 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 }
Parece que este comportamiento no se puede cambiar con una opción o mediante un archivo de configuración. La solución sugerida para detener el proceso de detección puede tener efectos secundarios indeseables. Un mejor enfoque es ocultar el proceso detenido de la pantalla. Para un script bash, esto se puede hacer con un subshell:
#!/bin/bash
(
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP ${BASHPID}
echo 'after stop' > ${OFILE}
)
Para otros shells puede que no sea tan sencillo, por ejemplo, para tcsh:
#!/bin/tcsh
(\
set OFILE='log' ;\
echo 'ok' > ${OFILE} ;\
kill -STOP `exec sh -c 'echo ${PPID}'` ;\
echo 'after stop' > ${OFILE} \
)
La diferencia clave es el método para obtener el PID del subnivel, más informaciónaquí.
Alternativamente, el script se puede iniciar sin modificaciones con unenvolturaguion:
#!/bin/bash
SCRIPTDIR="$(dirname "$(readlink -f -n "$0")")"
${SCRIPTDIR}/test.sh
Correr:
screen -d -m ./wrapper.sh