Search code examples
tclexpect

Multiple Spawn/expect issue


Currently, I am working on a script to automatize a Data Collector process. Through a long term run i have split these Collector script into four pieces. Now I want to start these Collectorscripts simultan, but i dont know how to do this. my Code ist working a bit:

package require Expect
log_user 0
set timeout 10200

spawn ./Log.tcl 2 5 1; set spawn1 $spawn_id
spawn ./Log.tcl 3 4 2; set spawn2 $spawn_id
spawn ./Log.tcl 7 8 2; set spawn3 $spawn_id
spawn ./Log.tcl 6 9 3; set spawn4 $spawn_id
expect -i $spawn1 eof {wait ; puts "--- 2,5 fertig ---"}
expect -i $spawn2 eof {wait ; puts "--- 3,4 fertig ---"}
expect -i $spawn3 eof {wait ; puts "--- 7,8 fertig ---"}
expect -i $spawn4 eof {puts "--- 6,9 fertig ---"}

this is run and made the thing. But if one job is ready before the other it will produces zombies. Is there a possibility to made this easy and beautiful? I have try a few thinks with exp_after, exp_background, $any_spawn_id with a while loop. But nothing worked. expect never get eof.


Solution

  • If you need to know the order in which the spawned commands finished, it is difficult to do with wait, but expect will accept a list of spawn ids to listen to simultaneously. For example,

    spawn sleep 2
     lappend allids $spawn_id
     set cmd($spawn_id) "sleep 2"
    spawn sleep 1
     lappend allids $spawn_id
     set cmd($spawn_id) "sleep 1"
    
    while { [llength $allids]>0 } {
     expect -i "$allids" eof {
      puts "eof on $expect_out(spawn_id) from cmd $cmd($expect_out(spawn_id))"
      set idx [lsearch -exact $allids $expect_out(spawn_id)]
      set allids [lreplace $allids $idx $idx]
     }
    }
    

    This runs 2 commands, sleep 2 and sleep 1, and appends each spawn id into the list allids. For convenience, the command is also noted in the array cmd indexed by the spawn id of that command.

    The list of all spawn ids is then given to expect eof using -i. When an eof is matched, the global variable $expect_out(spawn_id) contains the spawn id of the process causing the match. A message is printed after indexing this value in the cmd array.

    Finally, the spawn id with eof is removed from the list, and the loop repeated until the list is empty.

    Note, you cannot use exp_continue to continue the expect loop, as the -i value does not seem to be re-evaluated.