为何使用&能达到nohup的效果?

nohup

nohup的意思是忽略SIGHUP信号

守护进程

守护进程是一个在后台运行并且不受任何终端控制的进程。Unix操作系统有很多典型的守护进程(其数目根据需要或20—50不等),它们在后台运行,执行不同的管理任务。

用户使守护进程独立于所有终端是因为,在守护进程从一个终端启动的情况下,这同一个终端可能被其他的用户使用。例如,用户从一个终端启动守护进程后退出,然后另外一个人也登录到这个终端。用户不希望后者在使用该终端的过程中,接收到守护进程的任何错误信息。同样,由终端键入的任何信号(例如中断信号)也不应该影响先前在该终端启动的任何守护进程的运行。虽然让服务器后台运行很容易(只要shell命令行以&结尾即可),但用户还应该做些工作,让程序本身能够自动进入后台,且不依赖于任何终端。

守护进程没有控制终端,因此当某些情况发生时,不管是一般的报告性信息,还是需由管理员处理的紧急信息,都需要以某种方式输出。Syslog 函数就是输出这些信息的标准方法,它把信息发送给 syslogd 守护进程。

start=>start: 开始
fork=>operation: fork子进程
exit=>operation: 父进程exit
create=>operation: setsid()创建新会话
chdir=>operation: chdir("/")设置工作目录
umask=>operation: umask(0)重置文件权限掩码
close=>operation: close()关闭文件描述符
e=>end: 结束

start()->fork()->exit()->create()->chdir()->umask()->close()->e

孤儿进程

如果父进程先退出,子进程还没退出那么子进程将被托孤给init进程,这时子进程的父进程(PPID)就是init进程(1).

yiuked@localhost:~$ php test.php &
[2] 6613
yiuked@localhost:~$ ps -ajx
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     1     1     1 ?            0 Ss       0   0:00 /init
    1  6507  6507  6507 tty2         0 Ss       0   0:00 /init
 6507  6508  6508  6507 tty2         0 S     1000   0:00 -bash
 6508  6546  6546  6507 tty2         0 S     1000   0:00 /bin/sh ./test.sh
 6508  6613  6613  6507 tty2         0 S     1000   0:00 php test.php
 6546  6616  6546  6507 tty2         0 S     1000   0:00 sleep 1
 6508  6617  6617  6507 tty2         0 R     1000   0:00 ps -ajx
yiuked@localhost:~$ exit
logout

C:\Users\Administrator>wsl
yiuked@localhost:/mnt/c/Users/Administrator$ ps -ajx
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     1     1     1 ?            0 Ss       0   0:00 /init
    1  6546  6546  6507 ?            0 S     1000   0:00 /bin/sh ./test.sh
    1  6613  6613  6507 ?            0 S     1000   0:00 php test.php
    1  6662  6662  6662 tty1         0 Ss       0   0:00 /init
 6662  6663  6663  6662 tty1         0 S     1000   0:00 -bash
 6546  6677  6546  6507 ?            0 S     1000   0:00 sleep 1
 6663  6678  6678  6662 tty1         0 R     1000   0:00 ps -ajx

如上,php test.php &最开始的PPID为6508,在终端退出重新连接后,PPID变为了1,也就是init进程。

如果使用nohup会怎么样?

yiuked@localhost:~$ nohup ./test.sh &
[1] 11979
yiuked@localhost:~$ nohup: ignoring input and appending output to 'nohup.out'

yiuked@localhost:~$
yiuked@localhost:~$ ps -ajx
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     1     1     1 ?            0 Ss       0   0:00 /init
    1 11945 11945 11945 tty2         0 Ss       0   0:00 /init
11945 11946 11946 11945 tty2         0 S     1000   0:00 -bash
11946 11979 11979 11945 tty2         0 S     1000   0:00 /bin/sh ./test.sh
11979 11987 11979 11945 tty2         0 S     1000   0:00 sleep 1
11946 11988 11988 11945 tty2         0 R     1000   0:00 ps -ajx
yiuked@localhost:~$ exit
logout

C:\Users\Administrator>wsl
yiuked@localhost:/mnt/c/Users/Administrator$ ps -ajx
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     1     1     1 ?            0 Ss       0   0:00 /init
    1 11979 11979 11945 ?            0 S     1000   0:00 /bin/sh ./test.sh
    1 12001 12001 12001 tty1         0 Ss       0   0:00 /init
12001 12002 12002 12001 tty1         0 S     1000   0:00 -bash
11979 12015 11979 11945 ?            0 S     1000   0:00 sleep 1
12002 12016 12016 12001 tty1         0 R     1000   0:00 ps -ajx

使用nohup在终端退出时,依旧会变成孤儿进程,由init接管。

总结

通过&实现守护进程,加nohup与不加的区别在于,加了nohup,进程产生的标准输入与输出不会显示在终端干扰用户。 当终端关闭时,程序都不会退出,而是不init进程接管。

无论是通过&或者是nohup + &都只是通过孤儿进程的形式达到守护进程的效果,与httpd,nginx存中的守护进程有本质的区别。

Liunx启动过程

创建新进程
创建新进程
BOOT
BOOT
fork
fork
INIT
INIT
有账号输入EXEC
有账号输入EXEC
GETTY
GETTY
GETTY
GETTY
口令无误EXEC
口令无误EXEC
LOGIN
LOGIN
注销
注销
SHELL
SHELL
读取
读取
/etc/profile
/etc/profile
读取
读取
$HOME/.profile
$HOME/.profile
读取
读取
$HOME/.login
$HOME/.login
读取
读取
/etc/passwd
/etc/passwd
读取
读取
/etc/inittab
/etc/inittab
/etc/rc
/etc/rc
/etc/local.rc
/etc/local.rc

getty 用户登录

参考: 百度百科 https://baike.baidu.com/item/init%E8%BF%9B%E7%A8%8B/3042859?fr=aladdin