linux 后台運行進程:& , nohup


當我們在終端或控制台工作時,可能不希望由於運行一個作業而占住了屏幕,因為可能還有更重要的事情要做,比如閱讀電子郵件。對於密集訪問磁盤的進程,我們更希望它能夠在每天的非負荷高峰時間段運行(例如凌晨)。為了使這些進程能夠在后台運行,也就是說不在終端屏幕上運行,有幾種選擇方法可供使用。

后台執行

比較下 & 與 nohup:

  • & :后台運行,但用戶終端退出時(斷連),命令結束
  • nohup test.sh & : 后台運行,用戶終端退出時(斷連)依然保持運行,可使用標准輸入輸出

&

當在前台運行某個作業時,終端被該作業占據;可以在命令后面加上& 實現后台運行。e.g. sh test.sh &

適合在后台運行的命令有f i n d、費時的排序及一些s h e l l腳本。在后台運行作業時要當心:需要用戶交互的命令不要放在后台執行,因為這樣你的機器就會在那里傻等。不過,作業在后台運行一樣會將結果輸出到屏幕上,干擾你的工作。如果放在后台運行的作業會產生大量的輸出,最好使用下面的方法把它的輸出重定向到某個文件中:

command > out.file 2>&1 &
這樣,所有的標准輸出和錯誤輸出都將被重定向到一個叫做out.file 的文件中。

PS:當你成功地提交進程以后,就會顯示出一個進程號,可以用它來監控該進程,或殺死它。(ps -ef | grep 進程號 或者 kill -9 進程號)

nohup

使用&命令后,作業被提交到后台運行,當前控制台沒有被占用,但是一但把當前控制台關掉(退出帳戶時),作業就會停止運行。nohup命令可以在你退出帳戶之后繼續運行相應的進程。nohup就是不掛起的意思( no hang up / ignoring hangup signals) 即 忽略掛起信號一直在后台執行。

語法: nohup Command [ Arg … ] [& ]

e.g. $nohup python manage.py runserver &

使用時注意:

在當shell中提示了nohup成功后,還需要按終端上鍵盤任意鍵退回到shell輸入命令窗口,然后通過在shell中輸入exit來退出終端;如果在nohup執行成功后直接點關閉程序按鈕關閉終端的話,這時候會斷掉該命令所對應的session,導致nohup對應的進程被通知需要一起shutdown,起不到關掉終端后調用程序繼續后台運行的作用。

nohup command > myout.file 2>&1 &

無論是否將 nohup 命令的輸出重定向到終端,輸出都將附加到當前目錄的nohup.out 文件中。如果當前目錄的nohup.out文件不可寫,輸出重定向到$HOME/nohup.out文件中。如果沒有文件能創建或打開以用於追加,那么 Command 參數指定的命令不可調用。

2>&1解析:

command >out.file 2>&1 &

  • command>out.file是將command的輸出重定向到out.file文件,即輸出內容不打印到屏幕上,而是輸出到out.file文件中。

  • 2>&1 是將標准出錯 重定向到標准輸出,這里的標准輸出已經重定向到了out.file文件,即將標准出錯也輸出到out.file文件中。最后一個&, 是讓該命令在后台執行。

試想2>1代表什么,2與>結合代表錯誤重定向,而1則代表錯誤重定向到一個文件1,而不代表標准輸出;換成2>&1,&與1結合就代表標准輸出了,就變成錯誤重定向到標准輸出.

查看后台運行的命令

有兩個命令可以來查看,psjobs。區別在於 jobs 只能查看當前終端后台執行的任務,換了終端就看不見了。而ps命令適用於查看瞬時進程的動態,可以看到別的終端的任務

jobs

查看當前有多少在后台運行的命令

jobs -l選項可顯示所有任務的PID,jobs的狀態可以是running, stopped, Terminated。但是如果任務被終止了(kill),shell 從當前的shell環境已知的列表中刪除任務的進程標識。

“+”代表最近的一個任務(當前任務),“-”代表之前的任務。

只有在當前命令行中使用 nohup和& 時,jobs命令才能將它顯示出來。如果將他們寫到 .sh 腳本中,然后執行腳本,是顯示不出來的

比如執行下面這個腳本后,jobs 顯示不出來:

#!/bin/bash
nohup java -Dfile.encoding=UTF-8 -Dname=Runtime-Name -server -Xms128M -Xmx512M -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256M -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -jar test.jar $1 $2 $3 &

ps

nohup命令可以在你退出帳戶/關閉終端之后繼續運行相應的進程。關閉中斷后,在另一個終端jobs已無法看到后台跑得程序了,此時利用ps(進程查看命令)

ps -aux | grep "test.sh" #a:顯示所有程序 u:以用戶為主的格式來顯示 x:顯示所有程序,不以終端機來區分

關閉當前后台運行的程序

kill

  1. 通過jobs命令查看job號(假設為num),然后執行kill %num

  2. 通過ps命令查看job的進程號(PID,假設為pid),然后執行kill pid

前台進程的終止:ctrl+c

前后台進程的切換與控制

ctrl + z 命令

將一個正在前台執行的命令放到后台,並且處於暫停狀態。

fg 命令

將后台中的命令 調至 前台繼續運行。如果后台中有多個命令,可以用 fg %jobnumber(是命令編號,不是進程號)將選中的命令調出

bg 命令

將一個在后台暫停的命令,變成在后台繼續執行。如果后台中有多個命令,可以用bg %jobnumber將選中的命令調出。

思考

問題1-為什么ssh一關閉,程序就不再運行了

元凶:SIGHUP 信號

讓我們來看看為什么關掉窗口/斷開連接會使得正在運行的程序死掉。

在Linux/Unix中,有這樣幾個概念:

  • 進程組(process group):一個或多個進程的集合,每一個進程組有唯一一個進程組ID,即進程組長進程的ID。

  • 會話期(session):一個或多個進程組的集合,有唯一一個會話期首進程(session leader)。會話期ID為首進程的ID。
    會話期可以有一個單獨的控制終端(controlling terminal)。與控制終端連接的會話期首進程叫做控制進程(controlling process)。當前與終端交互的進程稱為前台進程組。其余進程組稱為后台進程組。

根據POSIX.1定義:

  • 掛斷信號(SIGHUP)默認的動作是終止程序。
  • 當終端接口檢測到網絡連接斷開,將掛斷信號發送給控制進程(會話期首進程)。
  • 如果會話期首進程終止,則該信號發送到該會話期前台進程組。

一個進程退出導致一個孤兒進程組中產生時,如果任意一個孤兒進程組進程處於STOP狀態,發送SIGHUP和SIGCONT信號到該進程組中所有進程。(關於孤兒進程參照:http://blog.csdn.net/hmsiwtv/article/details/7901711

結論:因此當網絡斷開或終端窗口關閉后,也就是SSH斷開以后,控制進程收到SIGHUP信號退出,會導致該會話期內其他進程退出。

簡而言之:就是ssh 打開以后,bash等都是他的子程序,一旦ssh關閉,系統將所有相關進程殺掉!! 導致一旦ssh關閉,執行中的任務就取消了

示例:

打開兩個SSH終端窗口,在其中一個運行top命令。

owen@swarm-manager-105:~$ top

在另一個終端窗口,找到top的進程ID為 38779,其父進程ID為38751,即登錄shell。

owen@swarm-manager-105:~$ ps -ef|grep top
owen      24007  23571  0 16:58 tty2     00:00:01 nautilus-desktop
owen      38779  38751  0 20:22 pts/1    00:00:00 top

使用pstree命令可以更清楚地看到這個關系:

owen@swarm-manager-105:~$ pstree -H 38779|grep top
        |-sshd-+-sshd---sshd---bash---top

使用ps -xj命令可以看到,登錄shell(PID 38751)和top在同一個會話期,shell為會話期首進程,所在進程組PGID為38751,top所在進程組PGID為38779,為前台進程組。

owen@swarm-manager-105:~$ ps -xj|grep 38751
 38750  38751  38751  38751 pts/1     38779 Ss    1000   0:00 -bash
 38751  38779  38779  38751 pts/1     38779 S+    1000   0:03 top

關閉第一個SSH窗口,在另一個窗口中可以看到top也被殺掉了。

owen@swarm-manager-105:~$ ps -ef|grep 38751
owen      40412  38966  0 20:52 pts/4    00:00:00 grep --color=auto 38751

問題2- 為什么守護程序就算ssh 打開的,就算關閉ssh也不會影響其運行?

因為他們的程序特殊,比如httpd –k start運行這個以后,他不屬於sshd這個進程組 而是單獨的進程組,所以就算關閉了ssh,和他也沒有任何關系!

[owen@centos-1 ~]$ pstree |grep http
        |-httpd---8*[httpd]

結論:守護進程的啟動命令本身就是特殊的,和一般命令不同的,比如mysqld_safe 這樣的命令 一旦使用了 就是守護進程運行。所以想把一般程序改造為守護程序是不可能,


免責聲明!

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



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