以前也学过一些shell,不过学得并不是很深入,动手写的代码的时间也不是很多。前不久将shell比较细的过了一遍,leader布置了任务让用shell写一个脚本将redis源码压缩包从一个服务器上传到另外一个服务器,同时在本服务器上传入命令,解压源码包并在另一个服务器上启动redis服务。
虽然学了一些shell,但是本次任务中需要使用的SCP和expect却是第一次使用,其中也遇到了一些问题,所以在这里总结一下。
现代的Shell对程序提供了最小限度的控制(开始,停止,等等),而把交互的特性留给了用户。 这意味着有些程序, 你不能非交互的运行,比如说passwd。简单点说就是你得手动输入密码,shell没有提供给你将密码直接在程序中一次性搞定的方法。
也正是因为如此,expect诞生了。
注意expect是独立于shell之外的,或者说他们完全不是一个东西(但是两者都是linux下很强大的工具)。当时我因为绝得expect是shell的一个补充,所以在expect中使用了很多shell的语法,呵呵!!!结果你懂的。
我在这里就简单说一下我用到的expect的基本语法,以及走过的坑,同时如果大家有愿望去学习一下的话我会在后面提供几个给我不少借鉴的网页,以便大家深入学习。
- 最简单的#!/usr/bin/env sh和#!/usr/bin/env expect 就懒得说了;
- 其次在expect中,传入参数的个数是用$argc访问的,然而在shell中$#。虽然很简单,但是shell中下面这几个参数还是记得的好:
3. shell中设置变量,$a="hello world",expect中 set a "hello world"
4. 在expect中查看变量的值:send_user "$a";
5. 在expect中执行shell的程序: spawn <shellCommand>
6. expect中查看传入的参数的值:[lindex $argv 1] [lindex $argv 2] [lindex $argv 3]...[lindex $argv n]
7. 特别有用的:用于进行交互的expect 和 send。我也没学得太深,只能大概举一个例子:
spawn ssh -l username 192.168.1.1
expect "*password:"
send "ispass\r"
就差不多这个样子吧!特别注意的是:send 后面的密码最后一定要跟一个\r,否则你等着错吧!!!
刚好到这里就再说说我遇到的一个大坑——情况是这样的,为了提高代码的复用性,导师都是让我不要把什么密码啊这一类的写死的,要么传参要么设置环境变量值,我选择了传参的方法,就比如下面这个程序:
hello.sh
#!/usr/bin/env expect
set host [lindex $argv 1]
set passwd [lindex $argv 2]
spawn ssh -l username $host
expect "*password:"
send "$passwd"
执行的命令是这样的:./hello.sh "192.168.1.1" "ispass\r"
好了,TMD。一直出错,不记得具体报什么错了,好像是提示密码错误。怎么会出错呢,纠结,纠结.....足足纠结几个小时啊!!!不知道错哪儿了
后来看到了这篇文档(http://blog.itpub.net/27042095/viewspace-745589/)的第一张图片,恍然大悟啊!!!赶快改正过来。
hello.sh
#!/usr/bin/env expect
set host [lindex $argv 1]
set passwd [lindex $argv 2]
spawn ssh -l username $host
expect "*password:"
send "$passwd\r"
执行命令:./hello.sh "192.168.1.1" "ispass"
8. 这个一定要注意:如果你在expect中利用ssh登录了某个服务器,你希望直接进入那个服务器(简单点说就是你现在是在服务器长操作了,看到的是服务器的文件)一定要使用interact
简单举一个例子吧:
#!/usr/bin/expect set timeout 30 spawn ssh -l username 192.168.1.1 expect "password:" send "ispass\r" interact expect eof
9.程序嘛!还是尽量有expect eof 和exit的好一点。
10. 最大的坑来了,expect的if用法:
if { <条件判断> } { <commands>... } 也许你没有仔细看:
- if的后面是大括号{},不是();
- if和后面的大括号之间是有一个空格的,你造吗?