bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.htmlhtml
注:这是一个没什么鸟用的功能。不过也算是一种拓展。node
一般在那些"一键化部署"的shell脚本中,可能须要使用ssh执行远程命令来实现一些简单的自动化,这些远程命令可能须要执行一段时间才能结束(如yum命令)。例如,远程ssh配置yum源,远程ssh安装软件包。shell
为了让脚本实现"并行"执行,这个远程ssh命令每每还会加上"-f"选项使其进入后台执行。此时,若是后续的远程任务正好要依赖于这个命令已经执行完成,那么咱们要判断前面的任务是否执行完成。例如,在配置软件的时候,必须先判断软件是否安装结束。数组
判断的方式挺简单,只需判断这个ssh进程是否存在就能够了。例如:bash
[root@node1 ~]# ssh 192.168.100.101 -f 'yum makecache'
[root@node1 ~]# killall -s 0 ssh
[root@node1 ~]# echo $?
这样的方法没错,也能应付绝大多数状况,但若是有多个远程后台命令的ssh进程,就没法知道具体是哪一个ssh进程。session
因而,能够采用另外一种方法,将执行远程命令的ssh进程放进后台,再用$!
来获取最近的后台ssh进程。例如:ssh
[root@node1 ~]# ssh 192.168.100.101 -f 'yum makecache' & echo $!
[1] 76115
76115
但这是错误的方法,若是你如今去查看ssh进程,你会发现进程号不是76115。tcp
[root@node1 ~]# pstree -p | grep 'ssh('
|-ssh(76116)
由于ssh在执行远程后台命令(加上"-f"选项)的时候,它自身会在创建ssh链接后再fork一个后台ssh进程用来执行远程命令。ui
也就是说,当ssh执行远程后台命令的时候,会有两个ssh进程:spa
注意,只有使用了"-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
......................................