Shell

程序在後台啟動之前被殺死

  • March 4, 2020

我正在使用script.sh包含命令的 bash 腳本cmd,在後台啟動:

#!/bin/bash
…
cmd &
…

如果我打開終端模擬器並執行script.shcmd則按預期在後台正確執行。也就是說,雖然script.sh已經結束,但cmd繼續在後台執行,PPID 為 1。

但是,如果我從前一個(或在桌面會話開始時,這是我的真實案例)打開另一個終端仿真器(比如說 xfce4-terminal),並script.sh執行

xfce4-terminal -H -x script.sh

cmd不再正確執行:它被script.sh. 使用nohup來防止這種情況是不夠的。我有義務sleep在它之後放一個命令,否則在與它分離之前被cmd, 的終止殺死。script.sh

cmd我發現在後台正確執行的唯一方法是set -m放入script.sh. 為什麼在這種情況下有必要,而不是在第一種情況下?為什麼這兩種執行方式script.sh(以及因此cmd)之間的行為差異?

我假設,在第一種情況下,監控模式沒有被啟動,正如你可以看到的set -o那樣script.sh

cmd你應該執行的程序將被和SIGHUP之間的信號殺死,任何包裝器或其他東西都沒有機會執行並產生任何影響。(您可以使用 進行檢查)fork()``exec()``nohup``strace

而不是nohup,您應該在執行後台命令之前在父 shell 中設置SIGHUPSIG_IGN(ignore) ;如果信號處理程序設置為“忽略”或“預設”,則該處置將通過fork()and繼承exec()。例子:

#! /bin/sh
trap '' HUP    # ignore SIGHUP
xclock &
trap - HUP     # back to default

或者:

#! /bin/sh
(trap '' HUP; xclock &)

如果您使用 執行此腳本xfce4-terminal -H -x script.sh,則後台命令 ( xclock &) 不會被SIGHUP發送時script.sh終止。

當會話領導者(在您的情況下“擁有”控制終端的程序script.sh)終止時,核心將從其前台程序組SIGHUP向所有程序發送一個;但是將啟用作業控制,並且以開頭的命令將被放入後台程序組中,並且不會由.set -m``&``SIGHUP

如果未啟用作業控制(非互動式腳本的預設設置),則以 開頭的命令&將在同一個前台程序組中執行,並且“後台”模式將通過重定向它們的輸入/dev/null並讓它們忽略 SIGINT和來偽造SIGQUIT

程序以這種方式從曾經作為前台作業執行但已經退出的腳本開始SIGHUP,因為它們的程序組(從其死去的父程序繼承)不再是終端上的前台。

額外說明:

xtermxfce4-terminal(可能還有其他基於 vte 的終端)之間的“保持模式”似乎不同。-e雖然前者將保持 pty 的主端打開,但後者將在程序執行或退出後將其撕掉-x,導致對從端的任何寫入都以EIO. 當仍有來自前台程序組的程序在執行時,xterm也會忽略消息(即它不會關閉)。WM_DELETE_WINDOW

引用自:https://unix.stackexchange.com/questions/480934