setsid、nohup、&区别
&
作用是将进程放到后台执行
$ sleep 2000 &
nuc 2228114 2225475 0 12:01 pts/3 00:00:00 sleep 2000
$ ps 2225475
2225475 pts/3 Ss 0:00 zsh
可以看到sleep 2000 的父进程是zsh,在将zsh关掉后,sleep 2000 进程也会退掉。
$ cat tt.sh
#!bin/bash
sleep 2000 &
sleep 20
$ ps -ef
nuc 2229204 1977958 0 12:06 pts/11 00:00:00 /bin/bash ./tt.sh
nuc 2229205 2229204 0 12:06 pts/11 00:00:00 sleep 2000
nuc 2229206 2229204 0 12:06 pts/11 00:00:00 sleep 20
20s 后
$ ps -ef
nuc 2229205 1399 0 12:06 pts/11 00:00:00 sleep 2000
如果在脚本里执行,在脚本运行期间,两个sleep的父进程都是bash进程,脚本运行结束后,sleep 2000还没有结束,它被托管给了1399进程,也就是systemd。此时终端退出也不会影响sleep 2000进程。但如果在脚本运行期间退出终端,这三个进程都会因为终端的退出而退出,因为sleep的父进程是bash,bash的父进程是zsh,也就是终端进程。
setsid
setsid命令 子进程从父进程继承了:SessionID、进程组ID和打开的终端。子进程如果要脱离这些,代码中可通过调用setsid来实现。,而命令行或脚本中可以通过使用命令setsid来运行程序实现。setsid帮助一个进程脱离从父进程继承而来的已打开的终端、隶属进程组和隶属的会话。 setsid会做下面这些事:
- 该进程会变成新会话的会话首进程(会话首进程即创建该会话的进程),此时新会话中只有该进程这么一个进程
- 该进程会变成一个新进程组的组长进程,新进程组ID就是该进程的PID
- 该进程与控制终端的联系被切断。
$ setsid sleep 200
nuc 2253367 1399 0 14:03 ? 00:00:00 sleep 200
可以看到sleep被托管给了systemd,此时不管终端退出与否,都不会影响sleep进程
nohup
当终端被挂断或伪终端程序被关掉,若终端的CLOCAL标志没有被设置,则SIGHUP信号会被发送到与该终端相关的控制进程(即会话首进程,通常为shell)。 而SIGHUP的默认行为是终止程序的运行。 当会话首进程终止,也会将SIGHUP信号发送给前台进程组中的每一个进程(根据shell的具体实现,还可能会把SIGNHUP发送给后台进程组)
而nohup的原理就是接收到SIGHUP信号后忽略掉,所有即便终端退出,终端派生出来的后台进程也不会退出。
$ cat tt.sh
#!bin/bash
sleep 2000 &
sleep 20
$ nohup ./tt.sh
nuc 2255350 1399 0 14:11 ? 00:00:00 /bin/bash ./tt.sh
nuc 2255351 2255350 0 14:11 ? 00:00:00 sleep 2000
nuc 2255352 2255350 0 14:11 ? 00:00:00 sleep 20
nuc 2255371 2225475 0 14:11 pts/3 00:00:00 ps -ef
可以看到,终端退出了,进程还在。
总结
- nohup 是靠截取SIGHUP信号
- setsid 是脱离父进程,改变其所属的终端、隶属进程和隶属回话
- & 是直接放到后台执行