zoukankan      html  css  js  c++  java
  • expect: spawn id exp6 not open while executing "expect eof"

    1.expect是基于tcl演变而来的,所以很多语法和tcl类似

    基本的语法如下所示:
    1.1 首行加上/usr/bin/expect
    1.2 spawn: 后面加上需要执行的shell命令,比如说spawn sudo touch testfile
    1.3 expect: 只有spawn执行的命令结果才会被expect捕捉到,因为spawn会启动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提示信息,eof和timeout。
    1.4 send和send_user:send会将expect脚本中需要的信息发送给spawn启动的那个进程,而send_user只是回显用户发出的信息,类似于shell中的echo而已。

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

    filename: account.sh,可以使用./account.sh newaccout来执行;

    #!/usr/bin/expect
    
    set passwd "mypasswd"
    set timeout 60
    
    if {$argc != 1} {
        send "usage ./account.sh $newaccount
    "
        exit
    }
    
    set user [lindex $argv [expr $argc-1]]
    
    spawn sudo useradd -s /bin/bash -g mygroup -m $user
    
    expect {
        "assword" {
            send_user "sudo now
    "
            send "$passwd
    "
            exp_continue
        }
        eof
        {
            send_user "eof
    "
        }
    }
    
    spawn sudo passwd $user
    expect {
        "assword" {
            send "$passwd
    "
            exp_continue
        }
        eof
        {
            send_user "eof"
        }
    }
    
    spawn sudo smbpasswd -a $user
    expect {
        "assword" {
            send "$passwd
    "
            exp_continue
        }
        eof
        {
            send_user "eof"
        }
    }
    

    注意点:

    第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
    "
    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下一个命令,但是不要依赖这种行为,很有可能今天还可以,明天就不能用了;

    其他

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

    #!/usr/bin/expect
    
    set timeout 30
    spawn ssh 10.192.224.224
    expect "password:"
    send "mypassword
    "
    expect "*$"
    send "mkdir tmpdir
    "
    
    expect "*$"
    

    timeout指expect等待命令至多等30seconds
    这个例子实际上是通过ssh去登录远程机器,并且在远程机器上创佳一个目录,我们看到在我们输入密码后并没有去expect eof,这是因为ssh这个spawn并没有结束,而且手动操作时ssh实际上也不会自己结束除非你exit;所以你只能expect bash的提示符,当然也可以是机器名等,这样才可以在远程创建一个目录。

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

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

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

  • 相关阅读:
    js获取当前时间,日期格式为年月日
    create-react-app里添加less
    react css 模块化
    react 点击父级元素 不触发子级元素click事件
    react-router-dom 实现路由左右滑动进入页面的效果
    vue路由左右侧滑动 react路由左右侧滑动
    react 父组件不能直接在子组件上加className,也得用props传递过去
    react 父组件调用子组件方法
    css滚动相关问题记录
    javascript异步编程的几种方法
  • 原文地址:https://www.cnblogs.com/netflix/p/12122750.html
Copyright © 2011-2022 走看看