考慮以下腳本:
#!/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