Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Calling functions after telnet spawn 1

Status
Not open for further replies.

rubberscissors

Technical User
Oct 11, 2001
21
US
I'm working on some test tools using expect, and I want to create a series of functions that each issue a series of commands to check and gather output. I'd like to be able to use these as part of a library which can be called from other scripts, but I'm running into the following problem:

Whenever the main function spawns a telnet session to the device being tested, if I send commands down from the main function they work, but if I try and send commands from another function called from within the main function, they don't work.

For example, I want to check port information using the command 'showPort'. If I spawn a telnet session from the main function, then expect the prompt, then send the command showPort, it works. If, on the other hand, I spawn a telnet session from the main function, then call another function (proc showport) which then expects the prompt and sends the command showPort, the command is never sent.

Has anyone else encountered this and know why it happens? Does the new function need to be told about the telnet session spawned from the main function? If so, does anyone know how to accomplish this? Any help would be appreciated.
 
The quick answer is that you have a problem with the scope of your variables. This is an aspect of Expect that isn't very obvious and causes quite a bit of confusion to Expect newcomers.

Expect makes extensive use of special variables during the execution of a script. You're probably already familiar with some of them, such as the expect_out array, into which Expect writes a variety of information about expect command matches. Another important one is spawn_id.

When you spawn a process, Expect generates a unique spawn ID to represent that process and stores the token in the spawn_id variable. Most other Expect commands implicitly use the value of the spawn_id variable to determine which process they're supposed to interact with. This can be quite handy, in that Expect supports spawning multiple processes under its control, and you can easily switch from one process to another by setting the spawn_id variable to the ID of the process you want to interact with.

Okay so far. The really tricky part is when you start working with Expect commands in procedures. When an Expect command writes to one of its special variables, it follows standard Tcl scoping rules. In other words, if the command is within a procedure, then the special variable (e.g., spawn_id or expect_out) is treated as a local variable unless you explicitly declare otherwise through a global or upvar command.

On the other hand, when an Expect command within a procedure reads one of its special variables (e.g., spawn_id or timeout), it can break standard Tcl scoping rules! The command first checks whether a variable of that name exists in the local scope, and if so it uses that value. On the other hand, if the variable doesn't exist in the local scope, the Expect command then also checks the global scope for that variable.

So anyway, the problem you're encountering is that you're spawning the process in a procedure, and so presumably spawn is writing the spawn ID of the process in a local spawn_id variable, which is of course automatically destroyed as soon as the procedure returns. Then in your other procedures, your send and expect commands are not going to have access to the spawn ID of the process you've created.

One solution would be to use the global command in your procedures to explicitly declare the spawn_id variable (and any other special Expect variables that you need) as being global. Another possibility would be to return the spawn ID of the process as the return value of your connection procedure, and then pass that ID to all other procedures that need access to it.

Which option you choose depends on how you plan to use your library procedures. If you assume that you'll only need a single process spawned in all of the scripts in which it will be used, the global variable approach will work fine. On the other hand, passing spawn ID as an argument will give you more flexibility for expansion should you need it later on.

For more information on spawn IDs, scoping, and other fun stuff, I highly recommend Don Libes's book "Exploring Expect," which tells you more than you'll ever want to know about all aspects of Expect. You can get the details from the official Expect web site, - Ken Jones, President, ken@avia-training.com
Avia Training and Consulting, 866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Thanks - although I had figured a way around it, the extra info is helpful and is actually going to make things a lot simpler than I had it originally!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top