Shell Expect 命令

本文介绍了expect,一种在shell脚本中实现自动化交互的强大工具,包括其关键命令如spawn、expect、send和set的应用,以及如何设置超时、使用示例和注意事项,如处理SSH、FTP登录和自动化任务的执行过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

expect可以实现shell实现不了的用户交互的需求。expect可以将交互写在一个脚本上,完成很多自动化的动作,比如ssh、ftp登陆等,都是需要交互需求的。expect是需要安装的,直接yum  -y install expect安装即可。

expect的四个关键命令为:spawn、expect、send、set,其中spawn是调用要执行的命令,expect是等待命令提示信息的出现也即捕捉用户提示信息,send是发送需要交互的信息来替代手工的输入,set则是输入变量值。

一、expect关键语法

1、关键语法

[#!/usr/bin/expect] 这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。 注意:这一行需要在脚本的第一行。

spawn              调用要执行的命令
expect               只有spawn执行的命令的执行结果才被expect捕捉到,主要包括标准输入的提示信息、eof和timeout。等待命令提示信息的出现,也就是捕捉用户输入的提示:
send                 发送需要交互的值,替代了用户手动输入内容
set                    设置变量值
interact             执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。
expect eof        这个一定要加,与spawn对应表示捕获终端输出信息终止,类似于if....endif

PS:expect脚本必须以interact或expect eof结束,执行自动化任务通常expect eof就够了。

2、常见设置

set timeout -1      设置expect永不超时  

set timeout 300   设置expect 300秒超时,如果超过300没有expect内容出现,则退出    

PS:为什么要设置超时时间,因为默认时间是10s,则在交互执行的过程中,很可能会断开,导致任务执行没完成就终止。我司的一个从远程ftp上同步文件的计划任务总是执行终止,后来设置了超时时间为-1就可以了。

二、expect的用法示例

1、一个简单的拉取文件的例子

    #!/usr/bin/expect -f
    set passwd "123456"     ##这个是你设置的密码
    set timeout -1          ##设置超时时间
    spawn sftp -P 2022 Jmsftp@ftp.jms.com
     
    expect "password:"
    send "$passwd\r"
    expect "sftp>"
    send "get -r data/201711*\r"
    expect "sftp>"
    send "exit\r"
    interact

2、一个小例子,用于linux下账户的建立:

    1 #!/usr/bin/expect
      2
      3 set passwd "mypasswd"    
      4 set timeout 60           
      5
      6 if {$argc != 1} {
      7     send "usage ./account.sh \$newaccount\n"
      8     exit
      9 }
     10
     11 set user [lindex $argv [expr $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         send_user "eof\n"
     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行: 对变量赋值的方法;
第4行: 默认情况下,timeout是10秒;
第6行: 参数的数目可以用$argc得到;
第11行:参数存在$argv当中,比如取第一个参数就是[lindex $argv 0];并且如果需要计算的话必须用expr,如计算2-1,则必须用[expr 2-1];
第13行:用spawn来执行一条shell命令,shell命令根据具体情况可自行调整;有文章说sudo要加-S,经过实际测试,无需加-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下一个命令,但是不要依赖这种行为,很有可能今天还可以,明天就不能用了;

3、下面这个例子比较特殊,在整个过程中就不能expect eof了

    1  #!/usr/bin/expect
     2   set mypassword=123456
     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进行处理,不多赘述。


PS:在shell脚本中插入expect命令,格式为如下


    #!/bin/sh
    expect <<!    ##开头
    spawn ssh xx@yyy
    expect "*Password*"
    send "xxx\r"
    expect ">"
    send "mkdir xxxxx\r"
    send "exit\r"
    expect eof
    !          ##结尾

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值