zoukankan      html  css  js  c++  java
  • 判断ssh远程命令是否执行结束

    bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html


    注:这是一个没什么鸟用的功能。不过也算是一种拓展。

    通常在那些"一键化部署"的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进程中的每一个?绝大多数时候都能使用的方式是直接从$!的结果加1来判断ssh的进程号。但是极少数情况下,fork出来的进程号不一定会是加1的。如果想要无比精确的判断,我个人没有想到好方法,只能通过比较愚笨的方式来实现判断:将每个后台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
    ......................................
    
  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/8785561.html
Copyright © 2011-2022 走看看