Linux 后台运行程序

为什么写这个呢,起因是看到了这个。。。

然后这是当事人的匿名回复

学好linux多重要(

几个概念

进程

linux 下的进程(Process)分为两种,一种叫做前台进程,一种叫做后台进程,还有一种叫做守护进程。

前台进程顾名思义,是在前台与用户交互的进程,用户可以通过终端来进行交互式的控制。此类进程运行时会占用终端,用户无法启动其它程序。

后台进程与前台进程的区别就是后台进程不会占用终端,用户可以在终端启动其它程序,但输出仍会发到终端的界面。

守护进程在服务端很常见,比如Web服务器的httpd,数据库的mysqld等,这类进程已经完全脱离终端,生命周期比较长。

linux 会给每个进程分配一个唯一编号,叫做PID

进程组

进程组(Process Group)是一堆进程的集合,因为进程之间往往是相互关联的,这时候可以把进程归为一组,便于操作。进程组的编号PGID取决于组长进程的PID。只要进程组当中有一个进程存在,那这个进程组就存在,不管组长进程是不是停止

作业

作业(Job)和进程组是类似的,只不过由作业里的进程产生的子进程不会属于这个作业。

会话

当用户登录系统之后就会产生一个会话(Session),一个会话包含一个会话控制进程(负责终端和系统的连接),一个前台进程组,若干个后台进程组。在会话中开启的进程都会成为改会话的子进程。

终端退出时会发生以下情况1

  1. 终端关闭时,信号(SIGHUP)被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)
  2. session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程
  3. 若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。

如何产生后台进程

目标

现在假设你也碰到了问题中的情况,程序没跑完,又怕关屏幕后程序中断怎么办?

其实也不难分析,关闭终端的时候会发生以下事情:

所以我们要实现以下目标:

  1. 让前台进程成为后台进程
  2. 让这个后台进程不受SIGHUP信号的影响而终止

方案

nohup 与 &

nohup指令可以运行一个命令,然后让命令忽略 SIGHUP 信号,而在命令尾部加上 & 可以使命令以后台方式运行,这时候程序会被加入到jobs里面.
默认用nohup执行命令时,命令的输出会被重定向至nohup.out,所以一般可以用如下指令运行程序把输出重定向至/dev/null:

1
nohup COMMAND > /dev/null 2>&1 &

nohup ... & 执行的程序仍然属于控制程序的子程序,所以关闭终端时SIGHUP 信号还是会发送给程序,只不过被 nohup 给忽略了。关闭终端之后,这个后台进程失去了父进程,成为了孤儿进程,会被init进程收养。

setsid

setsid 指令可以为指令开启一个新的会话,这样一来指令就不受当前终端影响了:

1
setsid COMMAND

ctrl-z, bg, fg, disown

如果程序忘了加 nohup 就执行了,又不想重新开始怎么办。
这时候ctrl-z就派上用场了,如果命令在前台运行时,用户按下了ctrl-z,那这个运行中的命令会被暂停,然后加入 jobs 里,例如

1
2
3
4
5
~ $ sleep 1000 
^Z
[1] + 5733 suspended sleep 1000
~ $ jobs
[1] + suspended sleep 1000

然后可以使用 bg %jobs里的编号 使程序在后台继续运行,或者用 fg %jobs里的编号 使程序继续在前台运行。

1
2
3
4
~ $ jobs
[1] + suspended sleep 1000
~ $ bg %1
[1] + 5733 continued sleep 1000

disown 指令可以把进程移出作业,使其成为后台进程,关闭终端时就不会收到SIGHUP信号,

1:linux sighup 信号 - 博客园