最近项目需求,需要写一些shell脚本交互,管道不够用时,expect可以很好的实现脚本之间交互,搜索资料,发现网上好多文章都是转载的,觉得这篇文章还不错,所以简单修改之后拿过来和大家分享一下~

1. expect是spawn: 后面加上需要执行的shell命令,比如说spawn sudo touch testfile
1.3 expect: 只有spawn执行的命令结果才会被expect捕捉到,因为spawn会启动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提示信息,Linux下账户的建立:
filename: account.sh,可以使用./account.sh newaccout来执行;

1 #!/usr/bin/expect
  2
  3 set passwd "mypasswd"【这个是你设置的密码】
  4 set timeout 60
  5
  6 if {$argc != 1} {
  7     send "usage ./account.sh exit
  9 }
 10
 11 set user [lindex $argv [$argc-1]]
 12
 13 spawn sudo useradd -s /bin/bash -g mygroup -m $user
 14
 15 expect {
 16     "assword" {
 17         send_user "sudo now\n"
 18         send "$passwd\n"
 19         exp_continue
 20     }
 21     eof
 22     {
 23         
 24     }
 25 }
 26
 27 spawn sudo passwd $user
 28 expect {
 29     "assword" {
 30         send "$passwd\n"
 31         exp_continue
 32     }
 33     eof
 34     {
 35         send_user "eof"
 36     }
 37 }
 38
 39 spawn sudo smbpasswd -a $user
 40 expect {
 41     "assword" {
 42         send "$passwd\n"
 43         exp_continue
 44     }
 45     eof
 46     {
 47         send_user "eof"
 48     }
 49 }

3. 注意点:
第3行: 对变量赋值的方法;
第4行: 默认情况下,timeout是10秒;
第6行: 测试,无需加-S亦可;
第15行:一般情况下,如果连续做两个expect,那么实际上是串行执行的,用例子中的结构则是并行执行的,主要是看匹配到了哪一个;在这个例子中,如果你写成串行的话,即
expect "assword"
send "$passwd\n"
expect eof
send_user "eof"
那么第一次将会正确运行,因为第一次sudo时需要密码;但是第二次运行时由于密码已经输过(默认情况下sudo密码再次输入时间为5分钟),则不会提示用户去输入,所以第一个expect将无法匹配到assword,而且必须注意的是如果是spawn命令出现交互式提问的但是expect匹配不上的话,那么程序会按照timeout的设置进行等待;可是如果spawn直接发出了eof也就是本例的情况,那么expect
"assword"将不会等待,而直接去执行expect
eof。
这时就会报expect: spawn id exp6 not open,因为没有spawn在执行,后面的expect脚本也将会因为这个原因而不再执行;所以对于类似sudo这种命令分支不定的情况,最好是使用并行的方式进行处理;
第17行:仅仅是一个用户提示而已,可以删除;
第18行:向spawn进程发送password;
第19行:使得spawn进程在匹配到一个后再去匹配接下来的交互提示;
第21行:eof是必须去匹配的,在spawn进程结束后会向expect发送eof;如果不去匹配,有时也能运行,比如sleep多少秒后再去spawn下一个命令,但是不要依赖这种行为,很有可能今天还可以,明天就不能用了;

4. 其他
下面这个例子比较特殊,在整个过程中就不能expect eof了:
 1  #!/usr/bin/expect
 2
 3  set timeout 30
 4  spawn ssh 10.192.224.224
 5  expect "password:"
 6  send "mypassword\n"
 7  expect "*$"
 8  send "mkdir tmpdir\n"
 9  expect "*$"
这个例子实际上是通过ssh去登录远程机器,并且在远程机器上创佳一个目录,我们看到在我们输入密码后并没有去expect
eof,这是因为ssh这个spawn并没有结束,而且手动操作时ssh实际上也不会自己结束除非你exit;所以你只能expect
bash的提示符,当然也可以是机器名等,这样才可以在远程创建一个目录。

注意,请不要用spawn mkdir tmpdir,这样会使得上一个spawn即ssh结束,那么你的tmpdir将在本机建立。

当然实际情况下可能会要你确认ssh key,可以通过并行的expect进行处理,不多赘述。

5. 觉得bash很多情况下已经很强大,所以可能用expect只需要掌握这些就好了,其他的如果用到可以再去google了。

6.实例:下面这个脚本是完成对单个服务器scp任务。

 1: #!/usr/bin/expect
 2: 
 3: set timeout 10
 4: set host [lindex $argv 0]
 5: set username [lindex $argv 1]
 6: set password [lindex $argv 2]
 7: set src_file [lindex $argv 3]
 8: set dest_file [lindex $argv 4]
 9: 
 10: spawn scp  11: expect {
 12:     "(yes/no)?"
 13:         {
 14:             send "yes\n"
 15:             expect "*assword:" { send "$password\n"}
 16:         }
 17:     "*assword:"
 18:         {
 19:             send "$password\n"
 20:         }
 21:     }
 22:  23: expect eof

注意代码刚开始的第一行,指定了expect的路径,与shell脚本相同,这一句指定了程序在执行时到哪里去寻找相应的启动程序。代码刚开始还设定了timeout的时间为10秒,如果在执行scp任务时遇到了代码中没有指定的异常,则在等待10秒后该脚本的执行会自动终止。

spawn代表在本地终端执行的语句,在该语句开始执行后,expect开始捕获终端的输出信息,然后做出对应的操作。expect代码中的捕获的(yes/no)内容用于完成第一次访问目标主机时保存密钥的操作。有了这一句,scp的任务减少了中断的情况。代码结尾的expect eof与spawn对应,表示捕获终端输出信息的终止。

有了这段expect的代码,还只能完成对单个远程主机的scp任务。如果需要 实现批量scp的任务,则需要再写一个shell脚本来调用这个expect脚本。

1: #!/bin/sh

  2:

 3: list_file=$1
 4: src_file=$2
 5: dest_file=$3
 6: 
 7: cat $list_file | while read line
 8: do
 9:     host_ip=`echo $line | awk '{print $1}'`
 10:     username=`echo $line | awk '{print $2}'`
 11:     password=`echo $line | awk '{print $3}'`
 12:     echo "$host_ip"
 13:     ./expect_scp $host_ip $username $password $src_file $dest_file
 15: done

很简单的代码,指定了3个参数:列表文件的位置、本地源文件路径、远程主机目标文件路径。需要说明的是其中的列表文件指定了远程主机ip、用户名、密码,这些信息需要写成以下的格式:

IP username password

中间用空格或tab键来分隔,多台主机的信息需要写多行内容。

这样就指定了两台远程主机的信息。注意,如果远程主机密码中有“$”、“#”这类特殊字符的话,在编写列表文件时就需要在这些特殊字符前加上转义字符,否则expect在执行时会输入错误的密码。

对于这个shell脚本,保存为batch_scp.sh文件,与刚才保存的expect_scp文件和列表文件(就定义为hosts.list文件吧)放到同一目录下,执行时按照以下方式输入命令就可以了:

  ./batch_scp.sh ./hosts.list /root/src_file /root/destfile

===============================================================================

下面我们来看一些expect的一些内部参数:

exp_continue [-continue_timer]
             The command exp_continue allows expect itself to continue executing rather than returning as it  normally would.  By  default  exp_continue  resets the timeout timer. The -continue_timer flag prevents timer from being restarted.

exp_version [[-exit] version]
             is useful for assuring that the script is compatible with the current version of Expect.

With  no  arguments, the current version of Expect is returned.  This version may then be encoded in
your script.  If you actually know that you are not using features of recent versions, you can specify an earlier version.

具体的用法还可以查看文档~

#!/bin/sh
# \
exec expect -- "$0" ${1+"$@"}
exp_version -exit 5.0
if {$argc!=2} {
    send_user "usage: remote-exec command password\n"
    send_user "Eg. remote-exec \"ssh user@host ls\; echo done\" password\n"
    send_user "or: remote-exec \"scp /local-file user@host:/remote-file\" password\n"
    send_user "or: remote-exec \"scp user@host:/remote-file local-file\" password\n"
    send_user "or: remote-exec \"rsync --rsh=ssh /local-file user@host:/remote-file\" password\n"
    send_user "Caution: command should be quoted.\n"
    exit
}
set cmd [lindex $argv 0]
set password [lindex $argv 1]
eval spawn $cmd
set timeout 600
while {1} {
    expect -re "Are you sure you want to continue connecting (yes/no)?" {
            # First connect, no public key in ~/.ssh/known_hosts
            send "yes\r"
        } -re "assword:" {
            # Already has public key in ~/.ssh/known_hosts
            send "$password\r"
        } -re "Permission denied, please try again." {
            # Password not correct
            exit
        } -re "kB/s|MB/s" {
            # User equivalence already established, no password is necessary
            set timeout -1
        } -re "file list ..." {
            # rsync started
            set timeout -1
        } -re "bind: Address already in use" {
            # For local or remote port forwarding
            set timeout -1
        } -re "Is a directory|No such file or directory" {
            exit
        } -re "Connection refused" {
            exit
        } timeout {
            exit
        } eof {
            exit
        }
}

注意用法:

Eg. remote-exec "ssh user@host ls; echo done" password
or: remote-exec "scp /local-file user@host:/remote-file" password
or: remote-exec "scp user@host:/remote-file local-file" password
or: remote-exec "rsync --rsh=ssh /local-file user@host:/remote-file" password
Caution: command should be quoted.

转自:http://blog.csdn.net/nero_g/article/details/53945654

shell脚本交互:expect学习笔记及实例详解的更多相关文章

  1. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  2. expect学习笔记及实例详解

    因为最近正在学习expect脚本,但是发现网上好多文章都是转载的,觉得这篇文章还不错,所以简单修改之后拿过来和大家分享一下~ 1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的 ...

  3. linux shell 脚本攻略学习20--awk命令入门详解

    awk生于1977年,创始人有三个,分别为 Alfred Aho,Peter Weinberger, 和 Brian Kernighan,名称源于三个创始人的姓的首字母. 作用:处理文本文件. awk ...

  4. linux shell 脚本攻略学习12--文件权限详解,chmod命令详解,chown命令详解,chattr命令详解

    文件权限详解 一.chmod命令详解 文件权限和所有权是Unix/Linux文件系统最显著的特征之一.linux中的每一个文件都与多种权限类型相关联,在这些权限中主要分类为3种: 用户(User)是文 ...

  5. linux shell 脚本攻略学习6-xargs详解

    xargs是一条Unix和类Unix操作系统的常用命令.它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题. 例如,下面的命令: rm `find /path -type f` ...

  6. Linux Shell脚本入门--wget 命令用法详解

    Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  9. Android学习笔记之Activity详解

    1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...

随机推荐

  1. Tips_of_JS 之 利用JS实现水仙花数的寻找与实现斐波那契数列

    一.水仙花数 1.啥是水仙花数? 水仙花数是指一个 n 位正整数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身.(例如:1^3 + 5^3+ 3^3 = 153) 2.利用JS实现对水 ...

  2. 一天搞定CSS:css选择器--07

    选择器:是指选择标签的方法 1.选择器类型 2.id选择器 代码演示 <!DOCTYPE html> <html> <head> <meta charset= ...

  3. idea live template

    最近正在研究如何给idea添加注释模板. 此篇文章是记录在写(开发)注释模板的过程中遇到的坑. 1. methodParameters() 当函数的参数列表为空的时候返回的是: [] 当函数的参数列表 ...

  4. homebrew & brew cask使用技巧及Mac软件安装

    homebrew 安装 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...

  5. python+selenium遇到鼠标悬停不成功可以使用js进行操作

    问题:在定位这种悬停后出现下拉操作的时候,尝试了使用move_to_element的方法 # ele_logout = br.find_element_by_xpath('/html/body/div ...

  6. GCTF2017部分write up

    Misc stage1 拿到题看到是一张图片隐写 用神器Stegsolve看看发现左上角藏着一张二维码 截下来,不能直接扫,需要反色处理一下 扫出来是一串十六进制 看头几个十六进制数发现是pyc文件 ...

  7. SQL中的cast()函数

    CAST函数用于将某种数据类型的表达式显式转换为另一种数据类型.CAST()函数的参数是一个表达式,它包括用AS关键字分隔的源值和目标数据类型. 语法: CAST (expression AS dat ...

  8. Treasure Hunt

    Treasure Hunt time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  9. nodejs+websocket制作聊天室视频教程

    本套教程主要讲解了node平台的安装,node初级知识.node 服务器端程序响应http请求,通过npm安装第三方包,websocket即时通讯.聊天页面界面制作.拖动原理.拖动效果.遮罩效果.定位 ...

  10. MySQL left join操作中 on与where放置条件的区别

    优先级 两者放置相同条件,之所以可能会导致结果集不同,就是因为优先级.on的优先级是高于where的. 1 1 首先明确两个概念: LEFT JOIN 关键字会从左表 (table_name1) 那里 ...