nohup-長期運行進程


我們經常會碰到這樣的問題,用 telnet/ssh 登錄了遠程的 Linux 服務器,運行了一些耗時較長的任務, 結果卻由於網絡的不穩定導致任務中途失敗。

解決辦法:
當用戶注銷(logout)或者網絡斷開時,終端會收到 HUP(hangup)信號從而關閉其所有子進程。因此,我們的解決辦法就有兩種:要么讓進程忽略 HUP 信號,要么讓進程運行在新的會話里從而成為不屬於此終端的子進程。


模擬一個斷開的會話,看一下前台進程是否還會正常運行:

[root@node1 ~]# cat b.sh 
#!/bin/bash
for((;;)) do
        sleep 1
        echo "no" >> /tmp/b.txt
done


第一個會話:
[root@node1 ~]# bash b.sh   #執行腳本,會占據整個當前會話頁面

新打開一個會話:
[root@node1 ~]# ps -ef | grep b.sh
root      34693  28170  0 11:32 pts/0    00:00:00 bash b.sh
...
[root@node1 ~]# kill -1 34693    #模擬第一個會話斷開的情況,發送SIGHUP信號

再次切換至第一個會話:
[root@node1 ~]# bash b.sh
Hangup                   #已經斷線
[root@node1 ~]#


nohup

nohup - run a command immune to hangups, with output to a non-tty

運行一個忽略hangups(SIGHUP)影響的命令,輸出到一個非tty

格式:
nohup COMMAND [ARG]...

示例:

[root@node1 ~]# nohup bash b.sh          #占據當前會話,使得當前會話不可執行其它命令
nohup: ignoring input and appending output to ‘nohup.out’   #如不指定日志輸出位置,默認輸出至當前目錄下的nohup.out文件中。


重新打開一個會話:
[root@node1 ~]# ps -ef | grep b.sh
root      25973  16490  0 09:56 pts/1    00:00:00 bash b.sh
[root@node1 ~]# kill -1 25973     #向進程發送SIGHUP信號,nohup進程還在運行。關閉上一個session會話,效果和kill -1效果一樣
[root@node1 ~]# 

nohup將標准輸出和標准錯誤缺省會被重定向到nohup.out文件中。一般我們可在結尾加上&來將命令同時放入后台運行,也可用>xxx.log 2>&1(將標准輸出和標准錯誤輸出至指定的文件中)來更改缺省的重定向文件名。

setsid

setsid - run a program in a new session

在一個新的會話中運行一個程序。

格式:
setsid program [arg...]

示例:

[root@node1 ~]# setsid bash b.sh      #使用setsid來代替nohup
[root@node1 ~]# jobs                  #后台無法查看
[root@node1 ~]# ps -ef | grep c.sh    #ps查找其進程,可以看到PID是43019,但PPID確為1(systemd)
root      43593      1  0 14:15 ?        00:00:00 bash b.sh
root      44473  43385  0 14:22 pts/1    00:00:00 grep --color=auto b.sh

[root@node1 ~]# pstree -H 43593 -p
systemd(1)─┬─NetworkManager(3403)─┬─{NetworkManager}(3543)
           │                      └─{NetworkManager}(3551)
           ├─agetty(3528)
           ├─auditd(2802)───{auditd}(2806)
           ├─bash(43593)───sleep(44564)             #因為父進程是1,不屬於某個終端的子進程,所以也就無法接收到HUP信號。但是不能使用專門指定這個此進程發送HUP信號,這樣是會中斷的。
           ├─chronyd(3472)
           ├─crond(3490)
		   ...
           ├─sshd(4154)───sshd(16488)─┬─bash(36542)───less(40656)
           │                          ├─bash(42726)
           │                          └─bash(43385)───pstree(44565)
		   ...

同樣的,在shell也有一種可以使用進程的PPID改成1的方法,使用`()`括起來並加上`&`,也和`setsid`效果一樣。 ``` [root@node1 ~]# (bash b.sh &) #后台執行命令 [root@node1 ~]# jobs #jobs無法查看 [root@node1 ~]# ps -ef | grep b.sh root 45631 1 0 14:30 pts/1 00:00:00 bash b.sh #PPID為1 root 45706 43385 0 14:31 pts/1 00:00:00 grep --color=auto b.sh [root@node1 ~]# kill -1 45631 #向進程發送HUP信號 [root@node1 ~]# ps -ef | grep b.sh #進程被中斷 root 45784 43385 0 14:31 pts/1 00:00:00 grep --color=auto b.sh [root@node1 ~]#

<br />




##jobs:
> 顯示當前會話下后台任務列表。也就是說,如果當命令切換至后台和想要顯示后台有哪些進程不是同一個會話,那么將查不出來有哪些后台進程。

**格式:**
`jobs [option]`

**常用選項:**
* -l:列出進程ID及其它信息
* -p:僅列出PID
* -n:僅列出自從上次輸出了狀態變化提示。run -> stop
* -r:顯示運行中的進程
* -s:顯示停止的進程

<br />
##fg:
> 將命令從后台作業提到前台終端運行。使用格式`fg 任務號`。任務號是由jobs命令獲取的第一列。

<br />

##bg:
> 使用格式`bg 任務號`。想要使用bg命令,首先對前台命令`ctrl+z`下放置后台成stop模式后,在對其使用bg命令才能像一開始在命令后添加`&`一樣后台運行。需要注意的是,如果掛起會影響到當前進程執行的結果,請慎用`ctrl+z`在`bg`。

<br />

**示例:**

[root@node1 ~]# bash b.sh #ctrl+z掛起進程至后台
^Z
[1]+ Stopped bash b.sh
[root@node1 ~]# jobs
[1]+ Stopped bash b.sh
[root@node1 ~]# bg 1 #后台繼續運行
[1]+ bash b.sh &
[root@node1 ~]# jobs #已經運行
[1]+ Running bash b.sh &
[root@node1 ~]#

[root@node1 ~]# bash #重新打開一個bash
[root@node1 ~]# jobs #查詢后台進程,查詢為空,所以jobs只能查詢當前會話的后台進程。
[root@node1 ~]#

[root@node1 ~]# exit #退出新的bash
exit
[root@node1 ~]# jobs #查看jobs
[1]+ Running bash b.sh &
[root@node1 ~]# fg 1 #調至前台運行
bash b.sh


<br />

**總結:**
`nohup`是使用進程本身忽略HUP信號從而達到可以后台運行不被意外中斷。`setsid`和shell中的`( &)`是將進程的父進程改為1,從而達到不受sshd連接的各種情況影響。
`jobs`,`bg`,`fg`三個命令只能在當前的會話終端上執行,一但會話終端意外剝離,就無法在操作。
<br />


參考資料:[https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/index.html](https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/index.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM