如何让Bash脚本启动二进制程序后与进程分离并安全关闭自身(Wine场景下异常问题)
我太懂你这个烦恼了——本来想让终端启动Wine程序后自动退出,结果倒好,连带着Wine进程一起被干掉了,试了& exit甚至加sleep延迟都没用,对吧?咱们先搞清楚问题根源,再给你靠谱的解决办法。
问题到底出在哪?
你用xfce4-terminal --execute bash --rcfile ini.sh启动时,bash是终端的直接子进程,而Wine又是bash的子进程。当bash执行exit时,终端会检测到子进程退出,默认会给整个会话组里的所有进程发送终止信号(比如SIGHUP)。
尤其是Wine这种“二进制调用二进制”的特殊情况:Wine本身是Linux进程,它还要启动Windows程序作为自己的子进程,整个进程链还没来得及完全脱离bash的会话控制,bash就已经退出了,导致终端的终止信号直接波及到了Wine及其子进程,所以才会出现“一起关掉”的情况。之前加sleep没用,是因为哪怕等17秒,Wine进程依然属于原会话组,终端关闭时还是会被波及。
靠谱的解决办法
下面这几种方法都是从进程会话/控制组层面彻底让Wine脱离bash和终端的控制,任选其一都能解决问题:
1. 用nohup忽略挂断信号
修改你的ini.sh脚本为:
cd /home/$USER/.wine/drive_c/shamela4; LC_ALL=ar_SA.UTF-8 nohup wine64 app/win/64/bin/shamela.exe >/dev/null 2>&1 & exit
nohup的作用是让进程忽略SIGHUP(挂断信号),即使父进程退出也能继续运行;>/dev/null 2>&1是把所有输出重定向到空设备,避免生成多余的nohup.out文件。
2. 用disown从bash作业列表移除进程
脚本可以这么写:
cd /home/$USER/.wine/drive_c/shamela4; LC_ALL=ar_SA.UTF-8 wine64 app/win/64/bin/shamela.exe & disown $! exit
$!代表刚启动的Wine进程的PID,disown会把这个进程从bash的作业控制列表中移除,这样bash退出时就不会给它发送终止信号了。
3. 用setsid创建全新会话
这种方法最彻底,直接让Wine成为新会话的领头进程:
cd /home/$USER/.wine/drive_c/shamela4; LC_ALL=ar_SA.UTF-8 setsid wine64 app/win/64/bin/shamela.exe & exit
setsid会创建一个完全独立的会话,Wine进程不再属于原来的终端会话组,不管bash和终端怎么退出,都不会影响到它。
备注:内容来源于stack exchange,提问作者Dumb

