首頁 > 軟體

判斷ssh遠端命令是否執行結束

2020-06-16 16:53:05

通常在那些"一鍵化部署"的shell指令碼中,可能需要使用ssh執行遠端命令來實現一些簡單的自動化,這些遠端命令可能需要執行一段時間才能結束(如yum命令)。例如,遠端ssh設定yum源,遠端ssh安裝軟體包。

為了讓指令碼實現"並行"執行,這個遠端ssh命令往往還會加上"-f"選項使其進入後台執行。此時,如果後續的遠端任務正好要依賴於這個命令已經執行完成,那麼我們要判斷前面的任務是否執行完成。例如,在設定軟體的時候,必須先判斷軟體是否安裝結束。

判斷的方式挺簡單,只需判斷這個ssh進程是否存在就可以了。例如:
[root@node1 ~]# ssh 192.168.100.101 -f 'yum makecache'
[root@node1 ~]# killall -s 0 ssh
[root@node1 ~]# echo $?


這樣的方法沒錯,也能應付絕大多數情況,但如果有多個遠端後台命令的ssh進程,就無法知道具體是哪個ssh進程。

於是,可以採用另一種方法,將執行遠端命令的ssh進程放進後台,再用$!來獲取最近的後台ssh進程。例如:
[root@node1 ~]# ssh 192.168.100.101 -f 'yum makecache' & echo $!
[1] 76115
76115

但這是錯誤的方法,如果你現在去檢視ssh進程,你會發現進程號不是76115。
[root@node1 ~]# pstree -p | grep 'ssh('
          |-ssh(76116)

因為ssh在執行遠端後台命令(加上"-f"選項)的時候,它自身會在建立ssh連線後再fork一個後台ssh進程用來執行遠端命令。

也就是說,當ssh執行遠端後台命令的時候,會有兩個ssh進程:
•第一個ssh進程是初始ssh進程,用於建立連線、傳送要執行的命令、fork新的ssh進程等,當這些任務結束後,這個ssh進程會消逝;
•第二個ssh進程是第一個ssh進程fork出來的新進程(偵錯的結果將顯示"debug1: forking to background"),用來執行遠端命令。它是後台進程,掛靠在init/systemd進程下。當遠端命令執行結束時,這個後台ssh進程會消逝。

注意,只有使用了"-f"選項,第一個ssh進程才會fork新的後台ssh進程,因為前台的任務(沒有使用"-f")可以直接在第一個ssh進程上執行。

第二個後台ssh進程無法用$!捕捉,$!捕捉到的只是&的後台,而對於ssh ... &中的"&"來說,它是將ssh連線進程(即第一個ssh進程)置於後台,而不是將fork出來的ssh後台進程再放入後台。所以上面的"echo $!"的結果76115比後台ssh進程號76116要小。

那麼有什麼好方法可以判斷多個遠端ssh進程中的每一個?沒有好方法(我個人還沒有想到),只能通過比較愚笨的方式來實現判斷:將每個後台ssh進程的pid號儲存起來(存放到每個變數中,或陣列中)。

例如,有兩個執行遠端命令的ssh進程:
ssh 192.168.100.101 -f 'sleep 50'
ssh_pid1=`ps x | awk '/ssh.*slee[p]/{print $1}' | tail -1`
ssh 192.168.100.101 -f 'sleep 60'
ssh_pid2=`ps x | awk '/ssh.*slee[p]/{print $1}' | tail -1`

# ssh_pid1 finished?
kill -0 $ssh_pid1
echo $?

# ssh_pid2 finished?
kill -0 $ssh_pid2
echo $?


最後補上ssh連線或執行遠端命令時,內部過程的詳細資訊。這些資訊使用ssh -vvv即可獲取,此處給出的是篩選後的一小部分。

當ssh建立連線或執行前台遠端命令(沒有使用"-f"選項)時:
OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to 192.168.100.101 [192.168.100.101] port 22.
debug1: Connection established                          # tcp連線建立
.....................
debug1: Authentication succeeded (publickey).
Authenticated to 192.168.100.101 ([192.168.100.101]:22).  # 使用者認證成功
debug1: channel 0: new [client-session]
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open                  # ssh連線建立
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.        # ssh連線進程進入互動式模式

[1]+  Stopped                ssh -vvvv 192.168.100.101

當執行遠端後台任務時(加上"-f"選項):
[root@node1 ~]# ssh -vvv 192.168.100.101 -f 'sleep 50' & echo $!
[1] 65570
65570                # echo $!得到的上一個後台進程位65570
[root@node1 ~]# OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to 192.168.100.101 [192.168.100.101] port 22.
debug1: Connection established.        # tcp連線建立
....................................
debug1: Authentication succeeded (publickey).    # 使用者認證成功
Authenticated to 192.168.100.101 ([192.168.100.101]:22).
debug2: fd 4 setting O_NONBLOCK
debug1: channel 0: new [client-session]
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open                # ssh連線建立
debug1: Requesting no-more-sessions@openssh.com
debug1: forking to background            # 注意此處:fork一個新ssh進程到後台
debug1: Entering interactive session.    # ssh連線進程進入互動式模式
debug2: callback start
......................................

本文永久更新連結地址https://www.linuxidc.com/Linux/2018-04/151816.htm


IT145.com E-mail:sddin#qq.com