當我們在終端或控制台工作時,可能不希望由於運行一個作業而占住了屏幕,因為可能還有更重要的事情要做,比如閱讀電子郵件。對於密集訪問磁盤的進程,我們更希望它能夠在每天的非負荷高峰時間段運行(例如凌晨)。為了使這些進程能夠在后台運行,也就是說不在終端屏幕上運行,有幾種選擇方法可供使用。
后台執行
比較下 & 與 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結合就代表標准輸出了,就變成錯誤重定向到標准輸出.
查看后台運行的命令
有兩個命令可以來查看,ps
和 jobs
。區別在於 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
-
通過jobs命令查看job號(假設為num),然后執行kill %num
-
通過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 這樣的命令 一旦使用了 就是守護進程運行。所以想把一般程序改造為守護程序是不可能,