bash 三种后台执行的区别

1,457 阅读2分钟

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 是脱离父进程,改变其所属的终端、隶属进程和隶属回话
  • & 是直接放到后台执行