前台任务 (foreground job) 会独占命令行窗口,只有运行完了或者手动中止,才能执行其他命令。
变成守护进程的第一步,就是把它改成 后台任务 (background job)。
mv a ../b &
只要在命令的尾部加上符号 & ,启动的进程就会成为后台任务。
让正在运行的前台任务变为后台任务,参考这个操作流程:
mv a ../b
任务启动。Ctrl + z
任务挂起。jobs
查看所有任务。bg %1
把标号为 1 的任务放入后台。disown -h %1
把标号为 1 的任务交给系统后台。后台任务有两个特点:
后台任务与前台任务的本质区别只有一个: 是否继承标准输入。
所以,执行后台任务的同时,用户还可以输入其他命令。
Linux 系统有这样一个设计:
因为前台任务收到了 SIGHUP 信号,所以会随着 session 的退出而退出。
后台任务是否也会收到 SIGHUP 信号由 Shell 的 huponexit 参数决定。
执行 shopt | grep huponexit
可以查看 huponexit 参数的值。
大多数 Linux 系统,这个参数默认关闭 (off)。因此,session 退出的时候,不会把 SIGHUP 信号发给后台任务。所以,一般来说,后台任务不会随着 session 一起退出。
通过后台任务启动守护进程并不保险,因为有的系统的 huponexit 参数可能是打开的 (on)。
更保险的方法是使用 disown
命令将指定任务从后台任务列表 (jobs
命令的返回结果) 之中移除。
一个后台任务只要不在这个列表之中,session 就肯定不会向它发出 SIGHUP 信号。
mv a ../b &
disown
执行上面的命令以后,server.js进程就被移出了后台任务列表。执行 jobs
命令验证,输出结果里面,不会有这个进程。
disown 的用法:
disown -r
移出所有正在执行的后台任务;disown -a
移出所有后台任务;disown -h
不移出后台任务,但是让它们不会收到 SIGHUP 信号;disown %2
disown -h %2
根据jobId,移出指定的后台任务。使用 disown 命令还有一个问题: 退出 session 后,如果后台进程与标准 I/O 有交互,它还是会挂。
var http = require('http');
http.createServer(function(req, res) {
console.log('server starts...'); // 加入此行
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World');
}).listen(5000);
启动上面的脚本,然后再执行 disown 命令。
node server.js &
disown
接着,退出 session,访问 5000 端口,会发现连不上。
因为后台任务的标准 I/O 继承自当前 session,disown 命令并没有改变这一点。
一旦后台任务读写标准 I/O,就会发现它已经不存在了,所以就报错终止执行。
为了解决这个问题,需要对"后台任务"的标准 I/O 进行重定向。
node server.js > stdout.txt 2> stderr.txt < /dev/null &
disown
上面这样执行,基本上就没有问题了。
还有比 disown
更方便的命令,就是 nohup
命令。
nohup node server.js &
nohup 命令对 server.js 进程做了三件事。
也就是说,nohup 命令实际上将子进程与它所在的 session 分离了。
注意,nohup 命令不会自动把进程变为后台任务,所以必须加上 & 符号。
nohup 命令:
使用 nohup 运行程序:
使用 & 运行程序:
一般两个一起组合使用不会受 Ctrl + C 和 Shell 关闭的影响:
nohup <command> &
最简单的后台运行。
nohup python main.py &
输出默认重定向到当前目录下 nohup.out 文件。
nohup python main.py >> main.log 2>&1 &
自定义输出文件 (标准输出和错误输出合并到 main.log)。
nohup python main.py &> main.log &
与上一个例子相同作用的简写方法。
nohup python main.py &> /dev/null &
不记录输出信息。
nohup python main.py &> /dev/null & echo $! > pidfile.txt
不记录输出信息并将程序的进程号写入 pidfile.txt 文件中,方便后续杀死进程。
使用 nohup 时,程序会自动将输出写入 nohup.out 文件中。如果程序不断向控制台输出,文件就会不停的变大。
如果不需要输出,可以用 /dev/null 解决这个问题。它相当于一个黑洞,任何输出到这个文件的东西都将消失。
nohup <command> >/dev/null 2>log &
只保留输出错误信息。
nohup <command> >/dev/null 2>&1 &
所有信息都不要。
2>&1 将错误信息重定向到标准输出。这使用到了 Linux 的重定向,其中 0 1 2 分别是标准输入、标准输出、标准错误输出,用来指定需要重定向的标准输入输出。默认情况下是标出输出,也就是 1 。
jobs -l
查看任务,返回任务编号和进程号。
bg %<jobnumber>
将一个在后台暂停的命令,变成在后台继续执行。如果后台中有多个命令,可以用 bg %<jobnumber>
将选中的命令调出。
fg %<jobnumber>
将后台中的命令调至前台继续运行。如果后台中有多个命令,可以用 fg %<jobnumber>
(是命令编号,不是进程号) 将选中的命令调出。