如何在Expect中与多个并发生成的spawn进程交互?
解决Expect多进程同时交互的问题
首先明确:Expect里根本没有expect_background这个命令,你要实现多进程并行交互,得靠多spawn实例+多分支expect监听+定向操作来实现。下面给你一套可运行的方案,解决你遇到的interact: spawn id exp5 not open报错问题。
先准备两个测试用的Shell脚本
t1.sh
#!/bin/bash while true; do echo "[T1] 请输入命令:" read input echo "[T1] 你输入了:$input" sleep 1 done
t2.sh
#!/bin/bash while true; do echo "[T2] 请输入指令:" read input echo "[T2] 收到指令:$input" sleep 1 done
核心Expect脚本 ex1.ex
这个脚本会同时启动两个进程,监听它们的输出,并支持你定向给指定进程发命令,避免交互混乱:
#!/usr/bin/expect -f # 启动两个进程并保存各自的spawn ID set t1 [spawn ./t1.sh] set t2 [spawn ./t2.sh] # 设置超时时间为无限,避免进程超时退出 set timeout -1 # 循环监听两个进程的输出,同时处理用户输入 proc interact_with_procs {t1 t2} { while {1} { expect { # 匹配T1的输出提示 "\[T1\] 请输入命令:" { # 允许用户输入并发送给T1 send_user "\n输入给T1的内容:" expect_user -re "(.*)\n" send $t1 "$expect_out(1,string)\r" exp_continue } # 匹配T2的输出提示 "\[T2\] 请输入指令:" { # 允许用户输入并发送给T2 send_user "\n输入给T2的内容:" expect_user -re "(.*)\n" send $t2 "$expect_out(1,string)\r" exp_continue } # 处理进程退出的情况,避免报错 eof { set current_spawn $expect_out(spawn_id) if {$current_spawn eq $t1} { send_user "\n[T1] 进程已退出\n" } else { send_user "\n[T2] 进程已退出\n" } # 可以选择退出脚本或者继续监听另一个进程 # exit } } } } # 调用交互函数 interact_with_procs $t1 $t2
关键说明
- 保存spawn ID:每个
spawn命令返回的ID必须存在变量里,后续操作(send/expect)都要指定这个ID,否则会默认操作最后一个spawn的进程,导致混乱。 - 多分支expect监听:用
expect的多条件匹配,同时监听两个进程的输出,匹配到对应提示后再处理用户输入,定向发送到目标进程。 - 避免spawn id报错:
- 确保进程没有提前退出:如果你的Shell脚本是一次性执行的,运行完就会退出,Expect再操作就会报
spawn id not open,所以测试脚本要用while true保持存活。 - 处理
eof事件:当某个进程退出时,捕获这个事件并提示,避免脚本崩溃。
- 确保进程没有提前退出:如果你的Shell脚本是一次性执行的,运行完就会退出,Expect再操作就会报
- 替代interact的定向操作:直接用
expect_user捕获用户输入,再用send $spawn_id "内容\r"定向发送,比原生interact更灵活,适合多进程场景。
运行方式
- 给三个脚本加执行权限:
chmod +x ex1.ex t1.sh t2.sh - 运行Expect脚本:
./ex1.ex
这样就能同时和两个进程交互,输入内容时会提示你是发给T1还是T2,不会出现交互混乱或报错的情况。
内容的提问来源于stack exchange,提问作者PatS
相关产品推荐
相关产品推荐

