美文网首页
Unix / Linux 下 nohup 和 & 的区别

Unix / Linux 下 nohup 和 & 的区别

作者: iyufei520 | 来源:发表于2018-09-18 23:16 被阅读0次

    声明:本文首发 简单教程,网址为 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 服务器,命令一般如下

    
    [yufei@www.twle.cn ~]$ python3 -mhttp.server 7777
    
    Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...
    
    

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

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

    
    [yufei@www.twle.cn ~]$ python3 -mhttp.server 7777 &
    
    [1] 27203
    
    

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

    
    [yufei@www.twle.cn ~]$ 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 命令查看所有后台任务

    
    [yufei@www.twle.cn ~]$ jobs
    
    [1]+  Running                python3 -mhttp.server 7777 &
    
    

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

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

    
    [yufei@www.twle.cn ~]$ 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 并不会把程序放在后台运行 」

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

    
    [yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777
    
    appending output to nohup.out
    
    

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

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

    
    [yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777
    
    appending output to nohup.out
    
    ^C[yufei@www.twle.cn ~]$
    
    

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

    
    [yufei@www.twle.cn ~]$ 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

    
    [yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777
    
    appending output to nohup.out
    
    

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

    
    [yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777
    
    appending output to nohup.out
    
    [1]+  Stopped                nohup python3 -mhttp.server 7777
    
    

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

    
    [yufei@www.twle.cn ~]$ exit
    
    logout
    
    There are stopped jobs.
    
    

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

    
    [yufei@www.twle.cn ~]$ exit
    
    logout
    
    Saving session...
    
    ...copying shared history...
    
    ...saving history...truncating history files...
    
    ...completed.
    
    [进程已完成]
    
    

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

    
    [yufei@www.twle.cn ~]$ ps aux | grep python
    
    luojianguo      28095  0.0  0.0  4295400    936 s000  S+  10:57下午  0:00.01 grep python
    
    

    结合 nohup 和 &

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

    
    [yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777 &
    
    [1] 28097
    
    [yufei@www.twle.cn ~]$ appending output to nohup.out
    
    

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

    
    [yufei@www.twle.cn ~]$ 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

    相关文章

      网友评论

          本文标题:Unix / Linux 下 nohup 和 & 的区别

          本文链接:https://www.haomeiwen.com/subject/bqtbnftx.html