1. 程式人生 > >讓程序在後臺可靠執行的幾種方法

讓程序在後臺可靠執行的幾種方法

簡介: 想讓程序在斷開連線後依然保持執行?如果該程序已經開始運行了該如何補救? 如果有大量這類需求如何簡化操作?

我們經常會碰到這樣的問題,用 telnet/ssh 登入了遠端的 Linux 伺服器,運行了一些耗時較長的任務, 結果卻由於網路的不穩定導致任務中途失敗。如何讓命令提交後不受本地關閉終端視窗/網路斷開連線的干擾呢?下面舉了一些例子, 您可以針對不同的場景選擇不同的方式來處理這個問題。

-----------------------------------------------------------------------------------------------

場景:

如果只是臨時有一個命令需要長時間執行,什麼方法能最簡便的保證它在後臺穩定執行呢?

解決方法:我們知道,當用戶登出(logout)或者網路斷開時,終端會收到 HUP(hangup)訊號從而關閉其所有子程序。因此,我們的解決辦法就有兩種途徑:要麼讓程序忽略 HUP 訊號,要麼讓程序執行在新的會話裡從而成為不屬於此終端的子程序。

1. nohup

nohup 無疑是我們首先想到的辦法。顧名思義,nohup 的用途就是讓提交的命令忽略 hangup 訊號。讓我們先來看一下 nohup 的幫助資訊:

NOHUP(1)                        User Commands                        NOHUP(1)

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

SYNOPSIS
       nohup COMMAND [ARG]...
       nohup OPTION

DESCRIPTION
       Run COMMAND, ignoring hangup signals.

       --help display this help and exit

       --version
              output version information and exit

可見,nohup 的使用是十分方便的,只需在要處理的命令前加上 nohup 即可,標準輸出和標準錯誤預設會被重定向到 nohup.out 檔案中。一般我們可在結尾加上"&"來將命令同時放入後臺執行,也可用">filename 2>&1"來更改預設的重定向檔名。

[[email protected] ~]# nohup ping www.ibm.com &
[1] 3059
nohup: appending output to `nohup.out'
[[email protected] ~]# ps -ef |grep 3059
root      3059   984
0 21:06 pts/3 00:00:00 ping www.ibm.com root 3067 984 0 21:06 pts/3 00:00:00 grep 3059 [[email protected] ~]#

2. setsid

nohup 無疑能通過忽略 HUP 訊號來使我們的程序避免中途被中斷,但如果我們換個角度思考,如果我們的程序不屬於接受 HUP 訊號的終端的子程序,那麼自然也就不會受到 HUP 訊號的影響了。setsid 就能幫助我們做到這一點。讓我們先來看一下 setsid 的幫助資訊:

SETSID(8)                 Linux Programmer’s Manual                 SETSID(8)

NAME
       setsid - run a program in a new session

SYNOPSIS
       setsid program [ arg ... ]

DESCRIPTION
       setsid runs a program in a new session.

可見 setsid 的使用也是非常方便的,也只需在要處理的命令前加上 setsid 即可。

[[email protected] ~]# setsid ping www.ibm.com
[[email protected] ~]# ps -ef |grep www.ibm.com
root     31094     1  0 07:28 ?        00:00:00 ping www.ibm.com
root     31102 29217  0 07:29 pts/4    00:00:00 grep www.ibm.com
[[email protected] ~]#

值得注意的是,上例中我們的程序 ID(PID)為31094,而它的父 ID(PPID)為1(即為 init 程序 ID),並不是當前終端的程序 ID。請將此例與nohup例中的父 ID 做比較。

3.&

這裡還有一個關於 subshell 的小技巧。我們知道,將一個或多個命名包含在“()”中就能讓這些命令在子 shell 中執行中,從而擴展出很多有趣的功能,我們現在要討論的就是其中之一。

當我們將"&"也放入“()”內之後,我們就會發現所提交的作業並不在作業列表中,也就是說,是無法通過jobs來檢視的。讓我們來看看為什麼這樣就能躲過 HUP 訊號的影響吧。

[[email protected] ~]# (ping www.ibm.com &)
[[email protected] ~]# ps -ef |grep www.ibm.com
root     16270     1  0 14:13 pts/4    00:00:00 ping www.ibm.com
root     16278 15362  0 14:13 pts/4    00:00:00 grep www.ibm.com
[[email protected] ~]#

從上例中可以看出,新提交的程序的父 ID(PPID)為1(init 程序的 PID),並不是當前終端的程序 ID。因此並不屬於當前終端的子程序,從而也就不會受到當前終端的 HUP 訊號的影響了。

-----------------------------------------------------------------------------------------------

場景:我們已經知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 訊號的影響。但是如果我們未加任何處理就已經提交了命令,該如何補救才能讓它避免 HUP 訊號的影響呢?

解決方法:這時想加 nohup 或者 setsid 已經為時已晚,只能通過作業排程和 disown 來解決這個問題了。讓我們來看一下 disown 的幫助資訊:

disown [-ar] [-h] [jobspec ...]
	Without options, each jobspec is  removed  from  the  table  of
	active  jobs.   If  the -h option is given, each jobspec is not
	removed from the table, but is marked so  that  SIGHUP  is  not
	sent  to the job if the shell receives a SIGHUP.  If no jobspec
	is present, and neither the -a nor the -r option  is  supplied,
	the  current  job  is  used.  If no jobspec is supplied, the -a
	option means to remove or mark all jobs; the -r option  without
	a  jobspec  argument  restricts operation to running jobs.  The
	return value is 0 unless a jobspec does  not  specify  a  valid
	job.

可以看出,我們可以用如下方式來達成我們的目的。

  • disown -h jobspec來使某個作業忽略HUP訊號。
  • disown -ah來使所有的作業都忽略HUP訊號。
  • disown -rh來使正在執行的作業忽略HUP訊號。

需要注意的是,當使用過 disown 之後,會將把目標作業從作業列表中移除,我們將不能再使用jobs來檢視它,但是依然能夠用ps -ef查詢到它。

但是還有一個問題,這種方法的操作物件是作業,如果我們在執行命令時在結尾加了"&"來使它成為一個作業並在後臺執行,那麼就萬事大吉了,我們可以通過jobs命令來得到所有作業的列表。但是如果並沒有把當前命令作為作業來執行,如何才能得到它的作業號呢?答案就是用 CTRL-z(按住Ctrl鍵的同時按住z鍵)了!

CTRL-z 的用途就是將當前程序掛起(Suspend),然後我們就可以用jobs命令來查詢它的作業號,再用bg jobspec來將它放入後臺並繼續執行。需要注意的是,如果掛起會影響當前程序的執行結果,請慎用此方法。

[[email protected] build]# cp -r testLargeFile largeFile &
[1] 4825
[[email protected] build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile &
[[email protected] build]# disown -h %1
[[email protected] build]# ps -ef |grep largeFile
root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFile
root      4853   968  0 09:46 pts/4    00:00:00 grep largeFile
[[email protected] build]# logout
[[email protected] build]# cp -r testLargeFile largeFile2

[1]+  Stopped                 cp -i -r testLargeFile largeFile2
[[email protected] build]# bg %1
[1]+ cp -i -r testLargeFile largeFile2 &
[[email protected] build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile2 &
[[email protected] build]# disown -h %1
[[email protected] build]# ps -ef |grep largeFile2
root      5790  5577  1 10:04 pts/3    00:00:00 cp -i -r testLargeFile largeFile2
root      5824  5577  0 10:05 pts/3    00:00:00 grep largeFile2
[[email protected] build]#

-----------------------------------------------------------------------------------------------

場景:我們已經知道了如何讓程序免受 HUP 訊號的影響,但是如果有大量這種命令需要在穩定的後臺裡執行,如何避免對每條命令都做這樣的操作呢?

解決方法:此時最方便的方法就是 screen 了。簡單的說,screen 提供了 ANSI/VT100 的終端模擬器,使它能夠在一個真實終端下執行多個全屏的偽終端。screen 的引數很多,具有很強大的功能,我們在此僅介紹其常用功能以及簡要分析一下為什麼使用 screen 能夠避免 HUP 訊號的影響。我們先看一下 screen 的幫助資訊:

SCREEN(1)                                                           SCREEN(1)

NAME
       screen - screen manager with VT100/ANSI terminal emulation

SYNOPSIS
       screen [ -options ] [ cmd [ args ] ]
       screen -r [[pid.]tty[.host]]
       screen -r sessionowner/[[pid.]tty[.host]]

DESCRIPTION
       Screen  is  a  full-screen  window manager that multiplexes a physical
       terminal between several  processes  (typically  interactive  shells).
       Each  virtual  terminal provides the functions of a DEC VT100 terminal
       and, in addition, several control functions from the  ISO  6429  (ECMA
       48,  ANSI  X3.64)  and ISO 2022 standards (e.g. insert/delete line and
       support for multiple character sets).  There is a  scrollback  history
       buffer  for  each virtual terminal and a copy-and-paste mechanism that
       allows moving text regions between windows.

使用 screen 很方便,有以下幾個常用選項:

  • screen -dmS session name來建立一個處於斷開模式下的會話(並指定其會話名)。
  • screen -list來列出所有會話。
  • screen -r session name來重新連線指定會話。
  • 用快捷鍵CTRL-a d來暫時斷開當前會話。
[[email protected] ~]# screen -dmS Urumchi
[[email protected] ~]# screen -list
There is a screen on:
        12842.Urumchi   (Detached)
1 Socket in /tmp/screens/S-root.

[[email protected] ~]# screen -r Urumchi

當我們用“-r”連線到 screen 會話後,我們就可以在這個偽終端裡面為所欲為,再也不用擔心 HUP 訊號會對我們的程序造成影響,也不用給每個命令前都加上“nohup”或者“setsid”了。這是為什麼呢?讓我來看一下下面兩個例子吧。

[[email protected] ~]# ping www.google.com &
[1] 9499
[[email protected] ~]# pstree -H 9499
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─2*[sendmail]
     ├─sshd─┬─sshd───bash───pstree
     │       └─sshd───bash───ping

我們可以看出,未使用 screen 時我們所處的 bash 是 sshd 的子程序,當 ssh 斷開連線時,HUP 訊號自然會影響到它下面的所有子程序(包括我們新建立的 ping 程序)。

[[email protected] ~]# screen -r Urumchi
[ro[email protected] ~]# ping www.ibm.com &
[1] 9488
[[email protected] ~]# pstree -H 9488
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─screen───bash───ping
     ├─2*[sendmail]

而使用了 screen 後就不同了,此時 bash 是 screen 的子程序,而 screen 是 init(PID為1)的子程序。那麼當 ssh 斷開連線時,HUP 訊號自然不會影響到 screen 下面的子程序了。

-----------------------------------------------------------------------------------------------

總結

現在幾種方法已經介紹完畢,我們可以根據不同的場景來選擇不同的方案。nohup/setsid 無疑是臨時需要時最方便的方法,disown 能幫助我們來事後補救當前已經在運行了的作業,而 screen 則是在大批量操作時不二的選擇了。

相關推薦

避免後臺程序被殺死的方法

Android的幾種程序 前臺程序     即與使用者正在互動的Activity或者Activity用到的Service等,如果系統記憶體不足時前臺程序是最後被殺死的。 可見程序     可以是處於暫停狀態(onPause)的Activity或者繫結在其上的Service,

程序後臺可靠執行方法

簡介: 想讓程序在斷開連線後依然保持執行?如果該程序已經開始運行了該如何補救? 如果有大量這類需求如何簡化操作? 我們經常會碰到這樣的問題,用 telnet/ssh 登入了遠端的 Linux 伺服器,運行了一些耗時較長的任務, 結果卻由於網路的不穩定導致任務中途失

Linux 技巧:程序後臺可靠執行方法

我們經常會碰到這樣的問題,用 telnet/ssh 登入了遠端的 Linux 伺服器,運行了一些耗時較長的任務, 結果卻由於網路的不穩定導致任務中途失敗。如何讓命令提交後不受本地關閉終端視窗/網路斷開連線的干擾呢?下面舉了一些例子, 您可以針對不同的場景選擇不同的方式來處理這

Linux 技巧:程序後臺可靠執行方法&CentOS 7通過Firewall開放防火牆埠

一.讓程序在後臺可靠執行的幾種方法 方法1 #nohup  【命令】 & 例: [[email protected] ~]# nohup ping www.ibm.com & 方法2 # (【命令】 &) 例:  # (ping www.i

Linux 技巧:進程在後臺可靠執行方法

stl 選項 con 中斷 program ng- dem 不同 正在 我們常常會碰到這種問題。用 telnet/ssh 登錄了遠程的 Linux server,執行了一些耗時較長的任務, 結果卻因為網絡的不穩定導致任務中途失敗。怎樣讓命令提交後不受本地關閉終端

進程在後臺可靠運行的方法

讓進程在後臺可靠運行的幾種方法 nohup setsid & disown screen讓進程在後臺可靠運行的幾種方法說明:我們經常會碰到這樣的問題,用 telnet/ssh 登錄了遠程的 Linux 服務器,運行了一些耗時較長的任務, 結果卻由於網絡的不穩定導致任務中途失敗。如何讓命令提交後不受本地關閉終

Linux 進程在後臺可靠運行的方法

lin post body nohup 所有 sid iso gpo 啟動 nohup 忽略 hang up 信號 setsid 使得父進程為1(init) & 使得父進程為1(init) disown 可以對已經啟動的進程進行忽略

nohup 進程在後臺可靠運行的方法

AR 列表 進程 opp ron bsp HA 環境 per 1. nohup nohup 無疑是我們首先想到的辦法。顧名思義,nohup 的用途就是讓提交的命令忽略 hangup 信號。 nohup 的使用是十分方便的,只需在要處理的命令前加上 nohup 即可,標準

檢視某個程序執行時間的方法

1.首先查出某個程序的pid,然後使用ps命令 [[email protected] ~]# jps 2640 Jps 2339 DataNode 2239 NameNode [[email protected] ~]# ps -p 2239 -o etime ELAPSE

Python呼叫shell命令的方法(在新程序執行shell命令)

有時候難免需要直接呼叫Shell命令來完成一些比較簡單的操作,比如mount一個檔案系統之類的。那麼我們使用Python如何呼叫Linux的Shell命令?下面來介紹幾種常用的方法: 1. os 模組 1.1. os模組的exec方法族 Python的exec系

Python指令碼暫停執行方法(轉載)

轉自:讓Python指令碼暫停執行的幾種方法 1.time.sleep(secs) 參考文件原文: Suspend execution for the given number of seconds. The argument may be a

根據程序控制代碼 獲得可執行檔案路徑 的方法

通過程序控制代碼,獲得可執行檔案的路徑,主要有以下幾種方法: 第一種方法:也是最常用的方法,是通過GetModuleFileNameEx函式獲得可執行檔案的模組路徑,這個函式從Windows NT 4.0開始到現在的Vista系統都能使用,向後相容性比較好。 【函式

C#啟動外部程序以及等待外部程序關閉的方法

string C# main 無限 完成 nbsp text enable geb 1. 啟動外部程序,不等待其退出。 2. 啟動外部程序,等待其退出。 3. 啟動外部程序,無限等待其退出。 4. 啟動外部程序,通過事件監視其退出。 // using Sy

windows下.bat程序開機自啟動的方法

win 命名 set 路徑 ima 窗口 ros 自啟動 obj 以下兩種方法,親測能夠執行的1、編寫VBS腳本新建腳本script.vbs,腳本內容如下:set ws=WScript.CreateObject("WScript.Shell")ws.Ru

歸納一下:C#執行緒同步的方法

 我們在程式設計的時候,有時會使用多執行緒來解決問題,比如你的程式需要在後臺處理一大堆資料,但還要使使用者介面處於可操作狀態;或者你的程式需要訪問一些外部資源如資料庫或網路檔案等。這些情況你都可以建立一個子執行緒去處理,然而,多執行緒不可避免地會帶來一個問題,就是執行緒同步的問題。如果這個問題處理不好,我們就

Android中使用非同步執行緒更新UI檢視的方法

在Android中子執行緒是不能更新ui的。 所以我們要通過其他方式來動態改變ui檢視, 1、runOnUiThreadactivity提供的一個輕量級更新ui的方法,在Fragment需要使用的時候要用getActivity.runOnUiThread開啟執行緒 這種方法最簡單,方便更新一些不需要判斷的

Java使用Executor執行Callable任務時的方法

多執行緒在需要返回值時,我們知道需要用到Callable和Future。Callable的cell方法可以返回一個值並且可丟擲異常,是對Runnable的很好的補充;Future表示了一個任務的週期,它提供了判斷任務狀態、獲取任務結果和取消任務等方法 。 下面演示三種使用Executor執行Call

java中執行緒同步的方法

方法一: 使用synchronized關鍵字  由於java的每個物件都有一個內建鎖,當用此關鍵字修飾方法時, 內建鎖會保護整個方法。在呼叫該方法前,需要獲得內建鎖,否則就處於阻塞狀態。 注: synchronized關鍵字也可以修飾靜態方法,此時如果呼叫該靜態方法,將會

執行緒(一):建立執行緒的方法

概括來說就是兩種:1、繼承Thread類,重寫run方法,然後start。不推薦這種,因為java的單繼承特性。 2、Thread類的建構函式中可以接受Runnable任務,所以只要是Runnable例項就可以作為引數給Thread 一般有兩種建立Runnable例項的方法(1)實現Runn

asp執行sql語句、儲存過程的方法

使用connection物件 會返回一個關閉的recordset記錄集,此記錄集不要再次宣告關閉 建議在update、insert、delete時使用 strCon="provider=sqloledb;data source=servername;initial catalog