IT博客汇
首页
精华
技术
设计
资讯
扯淡
权利声明
登录
注册
Shell应用(9):自动化批量编译
春秋十二月
发表于
2016-09-28 03:04:00
love
0
脚本概述
当需要在很多(比如几十至几百)台机器上编译同一程序时,如果一个个地手工拷贝源码、再编译,那么效率就很低,为了能大量节省手工、并行地编译,因此写了一个脚本,该脚本基于自动化脚本语言expect(expect基于tcl)实现,基本原理是针对每个远程主机,创建一个子进程,在该子进程内先调用scp拷贝源码到远程主机,再用ssh登录到远程主机、发送cd和make命令,交互期间的命令输出多用正则分析,最终的编译输出保存到当前目录output子目录下。其命令行参数说明如下:
●
第1参数为远程主机配置文件:一个多行文本文件,每行格式为IP 用户名 密码,空格符分隔,支持#注释。
●
第2参数为本地主机源码目录:要求该目录存在Makefile文件。
●
第3参数为远程主机目标目录:用于存放源码的位置。
脚本实现
拷贝源码
1
proc
copy_file
{host user srcdir dstdir passwd {timeout
10
} } {
2
if
[
catch
"
spawn scp
-rq
$srcdir $user@$host:$dstdir
"
msg] {
3
send_error
"
failed to spawn scp: $msg\n
"
4
exit
1
5
}
6
#send_user
"
match_max is [match_max]\n
"
7
8
expect_after eof
{
9
send_error
"
$host scp died unexpectedly\n
"
10
exit
1
11
}
12
expect {
13
"
(yes/no)?
"
{ send
"
yes\r
"
; exp_continue }
14
-
re
"
(?:P|p)assword:
"
{ send
"
$passwd\r
"
}
15
timeout { do_timeout
"
$host scp
"
}
16
}
17
18
expect {
19
full_buffe
r
{ exp_continue }
20
timeout
{ exp_continue }
21
eof
22
}
23
}
第2行调用spawn命令执行scp命令,并用catch捕捉错误;当执行成功后,第12行用expect等待远端输出(超时默认为10秒),当过程中网络连接断开时,会匹配到第8行的eof;当输出完成连接关闭时,会匹配到第21行的eof;如果输出太多超过expect内部的buffer时,会匹配到第19行的full_buffer,这里由于为了提高效率,使用了静默方式的scp,因些实际会匹配到第20行的timeout,不管匹配到哪种情况,都要继续直到eof。
执行编译
1
proc
do_make
{host user passwd subdir {timeout
10
} } {
2
if
[catch {spawn ssh $user@$host} msg ] {
3
send_error
"
failed to spawn ssh: $msg\n
"
4
exit
1
5
}
6
7
expect_after eof {
8
send_error
"
$host ssh died unexpectedly\n
"
9
exit
1
10
}
11
12
expect {
13
"
*yes/no
"
{ send
"
yes\r
"
; exp_continue }
14
-
re
"
(?:P|p)assword:
"
{ send
"
$passwd\r
"
}
15
timeout { do_timeout
"
$host ssh
"
}
16
}
17
wait_cmd $spawn_id passwd
18
19
send
"
cd $subdir\r
"
20
wait_cmd $spawn_id cd
21
22
send
"
make\r
"
23
wait_cmd $spawn_id make
24
25
send
"
exit\r
"
26
expect eof
27
}
关于spawn和expect的解释与上节
拷贝源码
相同,不同的是要先发送命令cd、等到命令提示符后(调用自定义函数wait_cmd),再发送make、等到命令提示符后,最后发送exit退出ssh、导致连接关闭,匹配到最后一行的eof。
主循环
1
set
f [open $file r]
2
set
curtime [clock seconds]
3
4
log_user
0
5
set
s {[:blank:]}
6
set
pattern
"
^(\[^#$s]+)\[$s]+(\[^$s]+)\[$s]+(\[^$s]+)
"
7
8
while
{ [gets $f line] !
=
-
1
} {
9
if
{ ![
regexp
$pattern [
string
trimleft $line] ? host user passwd] } {
10
continue
11
}
12
send_user
"
$host $user $passwd\n
"
13
if
{ ![
fork
] } {
14
15
set
timeout
30
16
set
filename output
/
${host}_[clock format $curtime
-
format %y.%m.%d_%H.%M.%S].log
17
18
log_file
-
noappend
-
a
$filename
19
20
copy_file $host $user $srcdir $dstdir $passwd
21
do_make $host $user $passwd $subdir $timeout
22
23
send_user
"
$host finish\n
"
24
exit
25
}
26
}
打开远程主机配置文件,读取每一行直到文件尾,忽略注释行,用正则提取IP、用户名和密码,创建子进程,按IP和当前时间命名log文件(由于前面调用log_user 0关闭了控制台输出,因此为了能记录输出到日志文件,一定要加-a选项),最后调用函数copy_file和do_make。
完整脚本下载:
autobuild.zip
春秋十二月
2016-09-28 11:04
发表评论