Betrachten Sie das folgende Skript:
#!/bin/bash
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP $$
echo 'after stop' > ${OFILE}
In einer interaktiven Shell wird das Skript gestoppt und die Ausgabe ist ok
. Wenn es jedoch gestartet wird als
screen -d -m ./test.sh
die Ausgabe ist after stop
. Verarbeitet der Bildschirm das Signal? Wie kann ein Prozess in einer Bildschirmsitzung angehalten werden?
Antwort1
Wahrscheinlich startet der Screen-Prozess den gestoppten Bash-Prozess neu. Ich habe Folgendes versucht (SIGSTOP-Signal an beide Prozesse senden):
test.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}
Bildschirmbefehl
screen -dmS sc_test ./test.sh
Logdatei
ok
screen pid 4453
test.sh pid 4454
Listenbildschirme
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.
Antwort2
Prüfung derQuellcode von GNU screen-4.0.2zeigte, dass screen überprüft, ob seine Kindprozesse gestoppt sind und dann versucht, sie mit SIGCONT fortzusetzen. Hier ist ein relevanter Teil davon 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 }
Dieses Verhalten lässt sich anscheinend nicht mit einer Option oder über eine Konfigurationsdatei ändern. Die vorgeschlagene Lösung, den Bildschirmprozess zu stoppen, könnte unerwünschte Nebenwirkungen haben. Ein besserer Ansatz besteht darin, den gestoppten Prozess auf dem Bildschirm auszublenden. Für ein Bash-Skript kann dies mit einer Subshell erfolgen:
#!/bin/bash
(
OFILE='log'
echo 'ok' > ${OFILE}
kill -SIGSTOP ${BASHPID}
echo 'after stop' > ${OFILE}
)
Bei anderen Shells ist es möglicherweise nicht so einfach, beispielsweise bei tcsh:
#!/bin/tcsh
(\
set OFILE='log' ;\
echo 'ok' > ${OFILE} ;\
kill -STOP `exec sh -c 'echo ${PPID}'` ;\
echo 'after stop' > ${OFILE} \
)
Der Hauptunterschied ist die Methode zum Abrufen der PID der Subshell. Weitere InformationenHier.
Alternativ kann das Skript ohne Änderungen mit einemVerpackungSkript:
#!/bin/bash
SCRIPTDIR="$(dirname "$(readlink -f -n "$0")")"
${SCRIPTDIR}/test.sh
Laufen:
screen -d -m ./wrapper.sh