1. 程式人生 > >ssh遠端執行nohup命令不退出

ssh遠端執行nohup命令不退出

Linux系統下,使用預設使用者root。遠端target機器的主目錄下有個指令碼test.sh,可執行許可權,內容只有一條命令:sleep 10

在本地機器上執行 ssh target "nohup ./test.sh &",結果ssh不立即退出,等test.sh執行完畢之後才退出。一般我們使用nohup命令是為了在斷開到某個伺服器的ssh連線之後,之前執行的命令仍然正常地在伺服器執行。但是前面的現象其實與nohup命令沒有什麼關係,只是ssh本身的問題;nohup其作用的前提是使用者使用ssh登入到伺服器上。至於跟nohup扯上關係,我猜是因為在大家的印象中上面這種nohup命令的執行方式應該是立即退出的,結果反差太大,所以當作了一個特別問題。相關的說明可以參見:

解決的方法是,手動在命令裡面指定重定向,即上面的命令換成:ssh target "nohup ./test.sh >/dev/null 2>&1 &",然後就OK。下面的分析表明了nohup命令與“ssh host "cmd"”方式的ssh命令沒有任何關係(因為這種方式不會涉及SIGHUP),所以換成ssh target "./test.sh >/dev/null 2>&1 &" 就可以了。

分析:

  一般處理ssh遠端執行某個命令的任務,在遠端目標機器上先建立一個sshd的子程序(父程序是最初始的sshd),然後由這個sshd程序啟動一個bash程序(如果使用bash程序)來執行傳遞過來的命令。  針對這次任務建立的sshd程序和bash程序在檔案描述符方面有一定關係:通常bash程序的0 1 2三個檔案描述符通過管道與sshd的相應檔案描述符聯絡起來。這可以通過查詢建立的sshd程序和bash程序在/proc檔案系統下的相應程序的fd目錄的詳細情況。ssh遠端執行命令這種建立ssh連線的方式在ps -ef 中顯示的sshd程序是有"sshd

[email protected]"標記。此sshd程序的命令可以通過命令“ps -ef | grep -v grep | grep 'sshd.*notty' | awk '{print $2}'”得到,而相關bash程序的PID可用$$獲取。遠端執行下面命令可以一步到位,得到比較結果:

  ssh target "TMPSPID=\$(ps -ef | grep -v grep | grep  -e 'sshd.*notty' | awk '{print \$2}');echo \$TMPSPID;ls -l /proc/\$TMPSPID/fd;echo \$\$;ls -l /proc/\$\$/fd" 

  如果遠端執行的命令是後臺執行,那麼可以發現新啟動的bash程序的父程序成了1,而輸入即描述符0重定向到了/dev/null。 nohup是防止程序被SIGHUP訊號中斷,正常使用的時候也會進行一些重定向操作,即當標準輸入/輸出/錯誤等是終端的時候,會對它們進行重定向。但是ssh遠端執行命令時,這些條件都不滿足,因為檔案描述符0,1,2(正常情況下)都被重定向到管道了。所以遠端執行nohup時不會進行相關重定向操作。而當遠端執行後臺命令的時候,雖然標準輸入被重定向到了/dev/null,但是標準輸出和錯誤還是管道, 所以針對這次任務啟動的sshd程序還不會結束。所以執行遠端命令時,還必須自己在命令列上重定向標準輸出和標準錯誤才行。

對於上面的test.sh指令碼,下面給出幾種命令執行執行方式:
  ssh target "./test.sh"           # 等待命令完成後退出;本地Ctrl+C中斷ssh會話,不會中斷test.sh的執行(bash父程序變為1)(與登入終端執行命令而終端連線斷開時的行為不一樣)
  ssh target "./test.sh &"        # 等待命令完成後退出;本地Ctrl+C中斷ssh會話,不會中斷test.sh的執行(bash父程序本來就為1)
  ssh target "nohup ./test.sh &"  # 等待命令完成後退出;本地Ctrl+C中斷ssh會話,不會中斷test.sh的執行(bash父程序本來就為1)
  ssh target "nohup ./test.sh >/dev/null 2>&1 &"  # 啟動test.sh執行後就會退出(bash父程序本來就為1)
 ssh target "./test.sh >/dev/null 2>&1 &"
             # 啟動test.sh執行後就會退出(bash父程序本來就為1),這也表明ssh不退出與nohup命令本身沒有什麼關係

實際上如先ssh登入target,執行./test.sh &,然後正常退出ssh(即exit命令),那麼./test.sh這個指令碼也不會終止,而且會將父程序換成1;如果不正常退出,而是直接關閉連線,那麼會導致./test.sh任務終止。

補充:

感覺上面的分析還不是很到位,因為簡單命令還不能夠顯示出真實情況,比如執行

ssh target "./test.sh"

在遠端機器上執行“ps -ef | grep 'test\|notty'”命令,結果如下

root     35929  3306  0 19:20 ?        00:00:00 sshd: [email protected]
root     35931 35929  0 19:20 ?        00:00:00 /bin/bash ./test.sh”

好像執行./test.sh的bash程序直接由顯示的sshd程序建立,其實情況應該不是這樣的。先執行一個稍複雜的命令:

ssh target "for w in a b c; do ./test.sh; done"

同樣使用上面的檢視命令可以看到如下結果:

root     36219  3306  0 19:29 ?        00:00:00 sshd: [email protected]
root     36221 36219  0 19:29 ?        00:00:00 bash -c for w in a b c; do ./test.sh; done
root     36228 36221  0 19:29 ?        00:00:00 /bin/bash ./test.sh

這就表明了其實有兩層程序關係,sshd ---- bash -c ----- bash,即sshd 先建立一個bash以bash -c的方式執行傳遞過來的作為命令的字串,然後再由這個bash建立執行./test.sh指令碼的子bash程序(這個可以建立多個)。而本地執行ssh host "cmd"形式命令要能迅速返回,必須滿足的條件是:該命令物件的sshd程序(一般是sshd: [email protected]),沒有子程序需要等待結束(靠將第一個bash搞成後臺程序,或者第一個bash會立即執行完命令自然退出——即它啟動一些後臺子程序), 而且沒有其他程序與它有管道連線關係(靠重定向解決,在第一個bash處或者所有第二層bash處都可以)。簡而言之,要ssh host "cmd"形式命令立即返回,在整個命令最後面新增“>/dev/null 2>&1 &”,是有保證的。注意,對於組合的命令, 可能需要放到{}中才行,比如“{ cmd; } >/dev/null 2>&1 &”這樣的形式。這是因為重定向只對單個簡單命令或單個複合命令有效。

下面通過一些實際例子的情況幫助大家認識(/dev/null也可以是某個本地檔案):

ssh target "for w in a b c; do ./test.sh >/dev/null 2>&1 0</dev/null; done"
ssh不返回,./test.sh一個一個啟動
ssh target "for w in a b c; do ./test.sh >/dev/null 2>&1 0</dev/null; done &"
ssh 不返回,./test.sh一個一個啟動。 第一個bash(由sshd啟動的bash -c)是後臺執行的,但是檔案描述符1和2還與sshd有管道連線,所以不返回
ssh target "for w in a b c; do ./test.sh >/dev/null 2>&1 0</dev/null; done >/dev/null 2>&1 &"
ssh立即返回,./tesh.sh一個接一個啟動
ssh target "for w in a b c; do ./test.sh ; done >/dev/null 2>&1 &"
ssh立即返回,./test.sh一個接一個啟動;由於執行./test.sh的bash是由第一個bash啟動的,而第一個bash執行了重定向,所以該bash也繼承了這些重定向,換言之這條命令與上條命令的效果一樣,即內層的./test.sh無需重定向了
ssh target "for w in a b c; do ./test.sh & done >/dev/null 2>&1 &"
ssh立即退出,./test.sh全部啟動,第一個bash也退出了
ssh target "for w in a b c; do ./test.sh & done >/dev/null 2>&1"
ssh立即退出(為什麼?因為第一個bash啟動三個./tesh.sh的bash程序後,退出了;而執行./test.sh的bash程序因為繼承了父bash的檔案描述符,所以沒有管道與sshd連線,因此ssh退出
ssh target "for w in a b c; do ./test.sh & done "
ssh不返回,因為執行./test.sh與sshd還有管道連線
ssh target "for w in a b c; do ./test.sh >/dev/null 2>&1 0</dev/null & done" 
ssh返回,因為第一個bash啟動三個子bash之後結束,而子bash與sshd之間又沒有管道上連線
ssh target "for w in a b c; do ./test.sh >/dev/null 2>&1 0</dev/null & done &"
同上,因為第一個bash啟動所有子程序後會退出,此時將第一個bash作為後臺程序已經意義不大
ssh target "./test.sh && ./test.sh >/dev/null 2>&1 &"
ssh不會返回
ssh target "{ ./test.sh && ./test.sh; } >/dev/null 2>&1 &" 
ssh會返回

相關推薦

ssh遠端執行nohup命令退出

Linux系統下,使用預設使用者root。遠端target機器的主目錄下有個指令碼test.sh,可執行許可權,內容只有一條命令:sleep 10 在本地機器上執行 ssh target "nohup ./test.sh &",結果ssh不立即退出,等test.sh

ssh登陸並執行命令退出

div bin rouge user 執行 登陸 data code nbsp 如果希望SSH登陸後先執行shell命令,可以這樣: ssh user@ip -t "cd /data ; /bin/bash" ssh登陸並執行命令不退出

ssh遠端執行命令並自動退出

ssh命令格式如下: usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D

ssh遠端執行命令退出

問題描述:         shell指令碼中需要用ssh遠端到其他伺服器執行命令,但是執行完成不返回。 解決方法: ssh [email protected]IP > /dev/null 2>&1 << EOF     rm -

SSH遠端執行Linux Shell命令

使用強大的paramiko Linux伺服器需要注意防火牆設定和SSH的開啟 注意執行的shell命令前提是Linux系統上有的 #!/usr/bin/python #coding=utf-8 import paramiko import threading import

ssh 遠端執行命令

SSH 是 Linux 下進行遠端連線的基本工具,不光可以登入,也可以遠端操作。接下來我們詳細講解一些常用的情況。 1、執行簡單的命令: 1)檢視某臺主機上的磁碟使用情況: $ ssh [email protected] "df -h" ***********

Python開源Devops定時任務管理系統(含定時呼叫介面、定時ssh遠端執行命令

 OpenMangosteen Devops定時呼叫http介面,定時執行SSH命令的WEB定時任務工具。本系統強依賴Flask-APScheduler的功能,只是拓展了web頁面部分。使用Pytho

ssh 遠端執行多個命令,有萬用字元要使用雙引號,沒有則可以不用

#!/bin/sh  for i in {2..25}  do         ip=10.161.21.$i         echo $ip         t=`ssh [email protected]$ip    "ls /home/unicom

ssh遠端執行命令

我們直接可以通過ssh命令,直接遠端機器執行命令,那麼我們是不是就可以通過用for迴圈的命令對遠端的機器安裝服務了呢。。 ssh   [email protected]  “yum -y install nginx” 通過上面的命令,可以實現批量

ssh免密碼遠端執行sudo命令

目的是執行下面的命令不需要輸入任何密碼! >ssh [email protected] "sudo command" 1. 在本地機器上生成祕鑰對兒 ssh-keygen -t rsa 一路回車後生成在~/.ssh/目錄下生成兩個檔案id_rsa和id

JSch連線SSH遠端執行命令

package test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arr

ssh遠端執行sed -i命令,替換的內容中含有雙引號的問題

在ssh 中執行sed -i 來替換匹配的字串,當替換的內容中包含雙引號"時,需要在轉義的同時,加上單引號'\"' 示例如下 <?xml version="1.0" encoding="UTF-8"?> <channel name=

ssh 遠端執行遠端機上的指令碼或命令

單命令執行: ssh [email protected] "cd /home ; ls" 今天 遠端執行命令發現了一個問題: 當執行下面命令 ssh -o ConnectTimeout=60 -qn [email protected] "cd

jenkins執行腳本退出

poll rip 遠程部署 提交 文件 code use put app ERROR: Exception when publishing, exception message [Exec timed out or was interrupted after XXX ms錯

PsTools遠端執行Windows命令

• 本篇文章是基於pstools 1.6版本。pstools是sysinternals出的一個功能強大的nt/2k遠端管理工具包。 它的主頁為http://www.sysinternals.com/ 下載地址為http://www.sysinternals.com/files/Pstool

ubuntu開啟ssh遠端連線(命令最少)

ubuntu開啟ssh遠端連線 方法: 1.sudo apt-get update 2.sudo apt-get install openssh-server 3.sudo ps -e |grep ssh 注意:附加命令 sudo service ssh start 就這

如何在ssh遠端linux伺服器時需要輸入密碼

目的:   期望A伺服器在對B伺服器執行ssh或者scp等命令的時候不需要輸入密碼 實現方法:   1.通過安裝sshpass服務   2.通過金鑰驗證的方式 操作過程:   一、通過sshpass的方式達到密碼非互動     1.安裝sshpass服務(centeros 7上可直接yum安裝,

詳解Linux下SSH遠端檔案傳輸命令scp

一:Linux ssh scp的簡介及作用: 在日常linux伺服器操作中,傳輸檔案是必不可少的操作。以前章郎蟲一直用他來翻牆,可以算是偏門,今天介紹SSH的正途啦。。。 scp就是secure copy的簡寫,用於在linux下進行遠端拷貝檔案的命令,和它類似的命令有cp,不過cp只是在本機進行拷貝不能跨

ssh遠端批量替換某個檔案中的字串,ssh遠端執行sudo指令

360xh01~360xh07先做祕鑰驗證然後把lw使用者sudo做無密碼驗證批量查詢某個使用者有沒有定時任務for i in [email protected] [email protected] [email protected] [ema

批量遠端執行shell命令工具

使用示例(使用了預設使用者root,和預設埠號22): ./mooon_ssh --h=192.168.4.1,192.168.4.2 -P=password -c='cat /etc/hosts' #include "mooon/net/libssh2.h" // 提供