題 如何完全從終端分離進程?


我在Ubuntu上使用Tilda(下拉終端)作為我的“命令中心” - 幾乎就像其他人使用GNOME Do,Quicksilver或Launchy一樣。

但是,我正在努力解決如何將一個進程(例如Firefox)從它啟動的終端中完全分離 - 即防止這樣的(非)子進程

  • 關閉始發終端時終止
  • 通過STDOUT / STDERR“污染”始發終端

例如,為了在“正確的”終端窗口中啟動Vim,我嘗試了一個簡單的腳本,如下所示:

exec gnome-terminal -e "vim $@" &> /dev/null &

但是,這仍然會導致污染(同樣,傳遞文件名似乎不起作用)。


278
2018-03-23 11:59


起源


這也是一個很好的問題。我認為將Bash視為一種編程語言是公平的 - 儘管這個問題的範圍確實可能更多地出現在系統管理員方面......
這是這個問題的副本 stackoverflow.com/questions/285015/... - Dana the Sane
重複:superuser.com/questions/177218/... - behrooz
您的用例本身並未描述完全脫離。 - jiggunjer


答案:


首先;一旦你開始一個過程,你可以通過先停止它來打開它(點擊 按Ctrl - ž)然後打字 bg 讓它在後台恢復。它現在是一個“工作”,它的 stdout/stderr/stdin 仍然連接到您的終端。

您可以通過在其末尾添加“&”來立即啟動後台進程:

firefox &

要在後台靜默運行它,請使用以下命令:

firefox </dev/null &>/dev/null &

一些額外的信息:

nohup 是一個你可以使用的程序 運行您的應用程序 這樣它的stdout / stderr可以被發送到一個文件,這樣關閉父腳本就不會對孩子進行SIGHUP。但是,在開始應用程序之前,您需要有先見之明才能使用它。因為這樣 nohup 工作,你不能只是 將它應用於正在運行的進程

disown 是一個bash內置函數,它從shell的作業列表中刪除一個shell作業。這基本上意味著你不能使用 fgbg 在它上面,但更重要的是,當你關閉你的shell時,它不會掛起或發送 SIGHUP 那個孩子了不像 nohupdisown 用來  該過程已經啟動並落後。

你是什​​麼 不能 do,是在啟動進程後更改進程的stdout / stderr / stdin。至少不是來自shell。如果你啟動你的進程並告訴它它的stdout是你的終端(這是你默認做的那樣),那麼該進程被配置為輸出到你的終端。你的shell與進程的FD設置沒有任何關係,這純粹是進程本身管理的東西。進程本身可以決定是否關閉它的stdout / stderr / stdin,但你不能使用你的shell強制它這樣做。

為了管理後台進程的輸出,你有很多來自腳本的選項,“nohup”可能是第一個想到的。但對於互動過程,你開始卻忘了沉默(firefox < /dev/null &>/dev/null &)真的,你做不了多少。

我建議你搞GNU screen。使用屏幕,當進程輸出變得麻煩並打開一個新進程時,您可以關閉正在運行的shell(^Ac)。


哦,順便說一下,不要用“$@“你在哪裡使用它。

$@手段, $1$2$3 ...,這將把你的命令變為:

gnome-terminal -e "vim $1" "$2" "$3" ...

這可能不是你想要的,因為 - 只需要  論點。使用 $1 表明你的腳本只能處理一個參數。

在你提供的場景中使用多個參數非常困難 gnome-terminal -e)因為 -e 只接受一個參數,這是一個shell命令字符串。您必須將您的參數編碼為一個。最好,最強大,但相當狡猾的方式是這樣的:

gnome-terminal -e "vim $(printf "%q " "$@")"

313
2018-03-23 13:18



非常感謝!可悲的是,我只能接受一個答案。我最終得到了“nohup $ @&> / dev / null&”和“alias wvim ='launch.sh gnome-terminal -x vim'”
多麼精彩,內容豐富的答案。 +1 - Teekin
當您關閉交互式bash shell時,@ Hi-Angel,bash HUP所有活動作業。當你^ Z和bg一個過程它仍然是一個工作,它是一個背景。要將其作為作業刪除,請使用 disown,然後這個過程將在你關閉shell之後繼續生存,因為bash不再HUP了。 - lhunath
不會用 $* 代替 $@ 修復單獨字符串的問題了嗎? - sjas
你不能做的是在啟動它之後更改進程的stdout / stderr / stdin。  - 不完全正確。使用 reptyr 為了這。 - Stefan Seidel


nohup cmd &

nohup 完全分離過程(守護它)


193
2018-03-23 12:17



雖然簡潔有價值,但完整性更有價值。雖然nohup是一個GNU coreutil,但是只有bash-only的答案(或者說不存在的答案)才適合。儘管如此,還是很好的答案 - Limited Atonement
nohup 只是忽略了 SIGHUP信號。它正常執行該過程。沒有守護進程。 - nemo
@nemo這意味著這個過程不是分離的,而是會分離出來的(並且是一個孩子的 init如果shell退出......對嗎? - Noldorin
@Noldorin是的。忽略在shell終止時發送的SIGHUP將使子進程繼續運行並重新定位到init。 - nemo
@nemo nohup也沉默標準輸入/輸出。跟進以完全分離為止。 - jiggunjer


如果你正在使用 bash,試試 disown [JOBSPEC]; 看到 bash的(1)

您可以嘗試的另一種方法是 at now。 如果您不是超級用戶,則允許使用 at 可能會受到限制。


53
2018-03-23 12:05



“disown”似乎不是一個內部bash命令(在我的機器上不可用,我使用bash)。正如Ben所說,“nohup”可能是一種更好(和標準)的做法。
從來沒有想過使用“at”,謝謝你的想法! - cadrian
at 把執行委託給別人,我喜歡它! +1 - Ninsuo
作為參考,這適用於 zsh 同樣。 - Coderer
也, disown 似乎沒有達到預期的效果 gnome-terminal - disown當終端退出時,ed進程仍然被終止。我很想知道為什麼/如何。 - Kyle Strand


閱讀這些答案,我的初步印像是發行 nohup <command> & 就足夠了。在gnome-terminal中運行zsh,我發現了 nohup <command> & 沒有阻止我的shell在退出時殺死子進程。雖然 nohup 是非常有用的,特別是對於非交互式shell,如果子進程沒有重置其處理程序,它只能保證這種行為 SIGHUP 信號。

就我而言, nohup 應該阻止掛斷信號到達應用程序,但子應用程序(在這種情況下為VMWare Player)正在重置它 SIGHUP 處理程序。因此,當終端仿真器退出時,它仍然可能會終止您的子進程。據我所知,這只能通過確保從shell的作業表中刪除進程來解決。如果 nohup 被內置的shell覆蓋,有時就是這種情況,但這可能就足夠了,如果它不是......


disown 是內置的shell bashzsh,和 ksh93

<command> &
disown

要么

<command> &; disown

如果你喜歡單行。這通常具有從作業表中刪除子進程的效果。這允許您退出終端仿真器,而不會意外地發信號通知子進程。無論如何 SIGHUP 處理程序看起來像,這不應該殺死你的子進程。

在被拒絕之後,該過程仍然是您的終端模擬器的一個孩子(玩 pstree 如果你想在運行中觀察這個,但在終端模擬器退出後,你應該看到它附加到init進程。換句話說,一切都應該如此,並且正如你想像的那樣。

如果你的shell不支持該怎麼辦 disown?我強烈主張改用一種,但如果沒有這種選擇,你會有一些選擇。

  1. screen 和 tmux 可以解決這個問題,但它們是更重的解決方案,我不喜歡為這麼簡單的任務運行它們。它們更適合您想要維護tty的情況,通常是在遠程計算機上。
  2. 對於許多用戶,可能需要查看您的shell是否支持zsh等功能 setopt nohup。這可以用來指定 SIGHUP當shell退出時,不應該將其發送到作業表中的作業。您可以在退出shell之前應用它,也可以將其添加到shell配置中 ~/.zshrc 如果你總是想要它。
  3. 找到一種編輯作業表的方法。我找不到辦法做到這一點 tcsh 要么 csh,這有點令人不安。
  4. 寫一個小C程序來分叉和 exec()。這是一個非常糟糕的解決方案,但源應該只包含幾十行。然後,您可以將命令作為命令行參數傳遞給C程序,從而避免作業表中的特定於進程的條目。

36
2018-01-22 17:08





  1. nohup $ COMMAND&

  2. $ COMMAND&disown

  3. setsid命令

我已經使用2號很長一段時間,但3號也一樣。另外,disown有'-h'的'nohup'標誌,可以用'-a'取消所有進程,並且可以用'-ar'取消所有正在運行的進程。

沉默由'$ COMMAND&> / dev / null'完成。

希望這可以幫助!


24
2017-08-25 14:39





我認為屏幕可能會解決您的問題


9
2018-03-25 01:51





在tcsh中(也可能在其他shell中),您可以使用括號來分離進程。

比較一下:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

對此:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

這會從作業列表中刪除firefox,但它仍然與終端綁定;如果你通過'ssh'登錄到這個節點,嘗試註銷仍然會掛起ssh進程。


8
2018-03-23 14:55





通過sub-shell解除tty shell run命令的關聯,例如

(命令)&

當退出使用終端關閉但進程仍然存在時。

檢查 -

(sleep 100) & exit

打開其他終端

ps aux | grep sleep

過程仍然存在。


6
2017-08-07 05:18



這正是我所需要的。我試圖為sublime文本添加一個控制台快捷方式,它完美無缺,這就是我最終的結果:(“/ opt / Sublime Text 2 / sublime_text”$ @)& - Ron E