Unix / Linux 下 nohup 和 & 的区别

声明:本文首发 简单教程,网址为 https://www.twle.cn/t/332#reply0

就在刚刚回家的路上,被前同事夺命三连 call 呼唤解决一个问题:为啥放在 crontab 里的命令放在 Shell 会进入假死状态?

那我就问了?什么是假死状态? 同事说,就是一直不会执行完毕,占着 Shell,不能做其它事情。

多次沟通后,才知道他写的这个是一个守护进程似的死循环程序,一旦启动除非发生意外,否则不会自己退出。

那肯定,很显然,会占着 Shell 啊。

nohup 和 &

我给的最简单的解决方案,就是按下组合键 CTRL+Z

其次给的是在执行的命令后添加一个 & 符号。 这个是最简单的后台执行模式,而且 & 号之前有无空格都没多大关系,之后有无空格也没关系。

如果只是告诉它这样,肯定是会出问题的,你能猜到么 ?

大家想到的第一个问题,肯定是退出 Shell 进程就会自动关闭。对的,没错,同事后来给我的答复是退出了进程还存在...囧,我一时不知道怎么解释,山高皇帝远,又没法远程和亲自查看。

但是,同事给我的第一个问题是:为啥一直输出日志啊?

我才想起来,忘记告诉它要 >/dev/null 2&>1 重定向日志。

后来又吧啦吧啦告诉它还可以使用 nohup 把要执行的命令扔到后台。

结果呢? 不说还好,一说人家就开问了,这两个命令有啥区别啊 ?

啊 ? 区别?

&nohup 都能把一个任务放在后台运行,但 & 命令会随着退出远程 Shell 而自动停止任务,而 nohup 则会一直继续运行,除非显示杀掉或者重启电脑

等等,这就完了?

我心慌了...只好回来继续查资料了。

Linux 程序生命周期里最重要的三个信号

来,考考大家,我们平时按的最多的两个组合键 CTRL+CCTRL+Z 分别会产生什么信号 ?

当我们退出远程 Shell 时,又会产生什么信号 ?

可以说,Linux 下有很多信号,但真正常用的且能够影响一个程序的信号就只有那么几个,比如

信号 说明
SIGINT 发送给前台进程组中的所有进程。常用于终止正在运行的程序,一般由 CTRL+C 组合键触发
SIGTSTP 发送给前台进程组中的所有进程,常用于挂起并暂停一个进程,一般由 CTRL+Z 组合键触发
SIGHUP 当用户退出 Shell 时,由该 Shell 开启的所有进程都会接收到这个信号,默认动作为终止进程

虽然 SIGINT 和 SIGHUP 的默认动作都一样,但人家是两个不同的信号,一定要牢记,不然等下你会分不清楚 &nohup 的区别的

& 的运行原理

经过上面的解释,想必你应该也清楚了,给任何命令加上 & 就会让该命令在后台执行

比如我们要在当前目录运行一个 Python3 服务器,命令一般如下

[[email protected] ~]$ python3 -mhttp.server 7777
Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...

这时候会发现,这个命令始终没有退出,我们没法继续在这个 Shell 上做其它事情,怎么办呢 ?

一种就是关闭当前 Shell,然后重新开启一个 Shell 执行相同的命令,并在命令的末尾添加 & 符号

[[email protected] ~]$ python3 -mhttp.server 7777 &
[1] 27203

这时候就会看到,我们的命令并没有占据 Shell 而是返回了一个进程号 [1] 27203[1] 表示任务 ID,而 27203 则表示进程号,我们可以使用 ps aux | grep python 查看下刚刚的命令是否仍在运行

[[email protected] ~]$ ps aux | grep python
luojianguo       27221   0.0  0.0  4286184    916 s007  S+   10:04下午   0:00.01 grep python
luojianguo       27203   0.0  0.1  4263348   3384 s007  S     9:56下午   0:00.35 /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python -mhttp.server 7777

看到 27203 了没有,对就是刚刚我们运行的命令。

至于任务 ID [1] ,在 Linux 中,每一个后台运行的程序,都叫一个任务,当在后台运行时,会分配一个任务 ID

我们可以使用 jobs 命令查看所有后台任务

[[email protected] ~]$ jobs
[1]+  Running                 python3 -mhttp.server 7777 &

这时候我们狂按下 CTRL+C 键会发现一定作用都没有,人家还是静静的运行着,从某些方面说 CTRL+C 发送的 SIGINT 是发送给所有前台进程的,后台运行的收不到也是自然的现象

然后,我们关闭 Shell,并重新打开 Shell,就会发现刚刚运行的后台任务也关闭了

[[email protected] ~]$ ps aux | grep python
luojianguo       27501   0.0  0.0  4295984    660 s000  U+   10:11下午   0:00.00 grep python

因此,可以说 & 运行的后台任务,会接收 SIGHUP 的信号,也就是对 SIGHUP 信号不免疫。

注意,如果你在本地演示,会发现进程还在,因为,本地 Shell 即使全部退出,Shell 会把这些后台任务交给登陆用户的 shell 去打理

nohup 并不会把程序放到后台执行

注意,很多文章都没有解释清楚,包括上面我的说法也是错的

「 nohup 并不会把程序放在后台运行 」

比如,我们使用下面的命令

[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out

除了提示已经把标准输出和标准错误输出到 nohup.out 文件外,人家还占据着 Shell 呢

如果你这后按下 CTRL+C 键就会发现程序立刻就退出了

[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
^C[[email protected] ~]$ 

使用 ps aux | grep python 就会看到刚刚运行的程序没了

[[email protected] ~]$ ps aux | grep python
luojianguo       27911   0.0  0.0  4258468    188 s001  U+   10:42下午   0:00.00 grep python

nohup 的真正作用是让程序忽略 SIGHUP 信号

nohup 命令的作用就是让程序忽略 SIGHUP 信号,但这里有一个前提,就是进程首先是在后台运行的,而不是暂停或挂起的

我们演示下一下,使用下面的命令运行一个 nohup

[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out

然后按下使用 CTRL+Z 命令先挂起当前 nohup 的命令

[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
[1]+  Stopped                 nohup python3 -mhttp.server 7777

可以看到我们的程序在后台是暂停的,但没有退出,如果我们使用 exit 命令,会提示有停止任务

[[email protected] ~]$ exit
logout
There are stopped jobs.

如果在此输入 exit 就会直接退出 Shell 并且会把所有的已经停止的程序关闭

[[email protected] ~]$ exit
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
[进程已完成]

然后我们重新开启一个 Shell 并使用 ps aux 命令,就会什么也看不到

[[email protected] ~]$ ps aux | grep python
luojianguo       28095   0.0  0.0  4295400    936 s000  S+   10:57下午   0:00.01 grep python

结合 nohup 和 &

如果我们过结合两者,比如使用下面的命令

[[email protected] ~]$ nohup python3 -mhttp.server 7777 &
[1] 28097
[[email protected] ~]$ appending output to nohup.out

然后我们运行 exit 命令退出当前 Shell

[[email protected] ~]$ appending output to nohup.out
exit
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

打开一个新的 Shell,输入 ps aux | grep python,就会发现之前的程序还存在

luojianguo       28171   0.0  0.0  4295984    668 s000  U+   10:59下午   0:00.00 grep python
luojianguo       28097   0.0  0.3  4271284  12556   ??  S    10:58下午   0:00.26 /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python -mhttp.server 7777

神奇吧

后记

真的很坑,我一直以为这两个命令都是用来把前台程序放到后台的,结果不是

  1. 只有 & 是把前台程序放到后台的
  2. nohup 只是把让正在运行的程序忽略 SIGHUP 信号而已

声明:本文首发 简单教程,网址为 https://www.twle.cn/t/332#reply0

原文地址:https://www.cnblogs.com/jankuo/p/9672045.html

时间: 2024-10-09 23:31:30

Unix / Linux 下 nohup 和 & 的区别的相关文章

【转】Linux下nohup命令实现退出终端后程序继续后台运行

Unix/Linux下一般想让某个程序在后台运行,很多都是使用&在程序结尾来让程序自动运行:但如果要想在退出终端后,程序依然还在后台运行,则要用nohup与&组合来实现. nohup 命令 用途:不挂断地运行命令 语法:nohup Command [ Arg ... ] [& ] 描述:nohup 命令运行由 Command参数和任何相关的Arg参数指定的命令,忽略所有挂断(SIGHUP)信号.在注销后使用 nohup 命令运行后台中的程序:要运行后台中的 nohup 命令,需要添

UNIX/Linux下C语言的学习路线

一.工具篇 “公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具. 1.操作系统    在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux系统有FreeBSD.RedHat Linux.SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等. 如果您一直使用Window

unix/linux下的共享内存、信号量、队列信息管理

在unix/linux下,经常有因为共享内存.信号量,队列等共享信息没有干净地清楚而引起一些问题.查看共享信息的内存的命令是ipcs [-m|-s|-q]. 默认会列出共享内存.信号量,队列信息,-m列出共享内存,-s列出共享信号量,-q列出共享队列清除命令是ipcrm [-m|-s|-q] id.-m 删除共享内存,-s删除共享信号量,-q删除共享队列.

linux 下 /bin /sbin 的区别 -- (转)

/bin,/sbin,/usr/bin,/usr/sbin区别 /  : this is root directory                root 用户根目录 /bin : commands in this dir are all system installed user commands    系统的一些指令 /sbin:  commands in this dir are all system installed super user commands  超级用户指令 系统管理

【归纳总结】Unix/linux下的进程管理(二):创建进程的函数及其应用、对比

创建进程的函数fork().vfork()和execl() 本次内容主要介绍Unix/linux下2个创建进程的函数fork和vfork以及它们的差别. 1.fork函数 (1)函数的格式 #include <unistd.h> pid_t fork(void); 函数功能: 主要用于以复制正在运行进程的方式来创建新的进程,其中新进程叫做子进程,正在运行的进程叫做父进程. 返回值: 函数调用成功时,父进程返回子进程的PID,子进程返回0,函数调用出错时,父进程返回-1,子进程没有被创建. 注意

linux 下nohup 使用

在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台: /usr/local/mysql/bin/mysqld_safe –user=mysql &.可是有很多程序并不想mysqld一样,这样我们就需要nohup命令,怎样使用nohup命令呢?这里讲解nohup命令的一些用法. nohup /root/start.sh & 在shell中回车后提示: [~]$ appending output

标准c库函数与Linux下系统函数库 区别 (即带不带缓冲区的学习)

我们都知道,C语言在UNIX/Linux系统下有一套系统调用(系统函数),比如文件操作open().close().write().read()等,而标准C语言的库函数中也有一套对文件的操作函数fopen().fclose().fwrite().fread()等..那么同样是对文件的操作函数,标C与UC有什么区别呢?是标C效率高还是UC效率高呢?今天就让我们来一探究竟. 程序作用:将0~999999这1000000个整型数据写入文件. 1.标准C实现大量数据写入文件: /*文件名test1.c*

linux下exit()和_exit()区别

平时一直在用exit()函数,但是今天看源码时竟然看到了_exit()函数,想知道它们的区别,所以就查查资料,写了下来!   #include<stdlib.h>   void exit(int status); 不像fork那么难理解,从exit的名字就能看出,这个系统调用是用来终止一个进程的.无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行.请看下面的程序: #include<stdlib.h>

Linux下关机命令的区别 (halt,poweroff,reboot,shutdown,init)

在Linux下一些常用的关机/重启命令. 1.shutdown shutdown命令安全地将系统关机.    有些用户会使用直接断掉电源的方式来关闭linux,这是十分危险的.因为linux与windows不同,其后台运行着许多进程,所以强制关机可能会导致进程的数据丢失﹐使系统处于不稳定的状态﹐甚至在有的系统中会损坏硬件设备.而在系统关机前使用shutdown命令﹐系统管理员会通知所有登录的用户系统将要关闭.并且login指令会被冻结﹐即新的用户不能再登录.直接关机或者延迟一定的时间才关机都是可