欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

expect: spawn id exp6 not open while executing "expect eof" 什么回事 ,,,,, expect ,,set timeout 10 详解 AG chatgt 有大用 有大大用 有大大大用

这个错误信息通常表示在使用 expect 脚本时,尝试读取一个尚未打开的进程的输出。具体来说,"spawn id exp6 not open" 意味着你尝试与一个未成功启动的子进程进行交互。

可能的原因和解决办法包括:

  1. 子进程未成功启动:确保你使用的 spawn 命令正确,并且子进程能够正常启动。例如,检查命令是否正确、路径是否有效。

  2. 命令执行失败:如果你在 spawn 后面调用的命令出现错误,expect 将无法与之交互。可以在命令前加上 puts 来输出调试信息,查看具体的错误。

  3. 超时设置:如果子进程需要一些时间才能启动,确保你的 expect 脚本有足够的时间等待。可以增加超时时间,例如使用 set timeout 10 

  4. 检查权限:确保你有权限执行该命令,尤其是在需要特权的情况下。

  5. 环境问题:有时,环境变量或系统配置问题也会导致子进程无法启动。检查你的环境设置。

如果你能提供更多的代码片段或上下文,我可以帮助你更具体地诊断问题。

   


   

这个错误信息 "expect: spawn id exp6 not open while executing 'expect eof'" 通常表示在使用 Expect 脚本时,尝试等待子进程结束(通过 expect eof)时,指定的 spawn ID(在这个例子中是 exp6)没有打开。

可能的原因包括:

  1. 子进程未成功启动:确保你在 spawn 命令中正确启动了一个子进程。如果子进程没有成功启动,spawn ID 将不会有效。

  2. 子进程已经结束:如果子进程在你调用 expect eof 之前就已经结束,Expect 将无法找到该 spawn ID。

  3. 错误的 spawn ID:检查你的代码,确保你在使用 expect eof 时使用的是正确的 spawn ID。

解决方案

  • 确保在调用 expect eof 之前,子进程已成功启动并处于运行状态。

  • 使用 expect 的其他命令(如 expect 或 timeout)来处理可能的错误情况。

  • 检查脚本中的逻辑,确保 spawn ID 是有效的。

如果你能提供更多的代码或上下文,我可以帮助你更具体地诊断问题。


   


   


   


   

expect脚本注意事项expect  :spawn id exp6 not open

expect{    }   第一个{要用tab建回车, 否则会报expect  :spawn id exp6 not open 错误 是书写有错误

image.png            

 image.png            

 

文章知识点与官方知识档案匹配,可进一步学习相关知识

云原生入门技能树首页概览19869 人正在系统学习中

来自 https://blog.csdn.net/m0_67085438/article/details/135616134            


           


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 而
已。

2. 一个小例子,用于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 \$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. 注意点:

第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 与“{ ”之间直接必须有空格或则TAB间隔,否则会出麻烦,会报错 invalid command name "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 "*$"
send "mkdir tmpdir\n" #远程执行命令用send发送,不用spawn
9 expect "*$" #注意这个地方,要与操作系统上环境变量PS1相匹配,尤其是有PS1有空格的情况下,一定在expct "*$ "把空格加上,加不上你就完蛋了。我试过。
这个例子实际上是通过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  $src_file $username@$host:$dest_file
 
 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: expect "100%"
 
 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文件吧)放到同一目录下,执行时按照以下方式输入命令就可以了:

1.jpg

2.jpg

3.jpg

1.jpg

2.jpg

11.jpg

12.jpg

13.jpg

14.jpg

普通分类: