Linux TCL Expect

From Ever changing code
Jump to navigation Jump to search

Expect is an automation and testing tool used to automate a process that receives interactive commands. If you can connect to any machine using ssh, telnet, ftp, etc then you can automate the process with an expect script. This works even with local programs where you would have to interact with a script or program on the command line.

Expect is an extention to the Tcl scripting language so it uses all of Tcl's syntax.

Most scripts begin by spawning the process they want to interact with. This is done with the "spawn" command. Like "spawn ssh user@host or spawn ftp host". Then you can begin checking for output with the command "expect". Expect uses regular expressions to find patterns in the output, and when it matches a pattern you send it command with the "send" command. In the simplest form that is how expect works. You start the process and look for patterns in the output. Then send commands based on the matches from the output.


sudo apt-get install expect

Most used commands and descriptions

The expect command will wait until one of the patterns given matches the output of a spawned process, a specified time period has passed, or an end-of-file is seen. Since you can give the expect command multiple things to match on you can have it do different things when it matches. The first sentence bares repeating, but I will try to expand on it. Expect will constantly loop through the multiple given patterns until a match is found. Expect will match the first pattern it finds in the order you specified them. When it finds a match it will execute any commands given and keep following any more nested commands until it hits the last command. It will never return to the calling block. It then moves onto the next part of the script.

If at any time there are no matches it will timeout. If the pattern keyword (match word) "timeout" is used you can have it perform an action when the timeout happens.

If an eof is returned it will exit the spawned process and move on. If you use "eof" as a pattern keyword then you can have it also perform an action if an eof happens.

You can also use the pattern keyword called "default" that can perform an action if either eof or timeout are reached. We will see how to use this to make great error messages later.

Sends string to the current process. Usually this is a command followed by a return character (/r) like send "yourpassword\r". You use the expect command to match the output and decide what to send the current process.
send -s instructs to send characters slow at the rate set in send_slow special variable.
send -h instructs to send send characters as send_human, eg: set send_human {.1 .3 1 .05 2} emulates fast and consistent typist, read more...
Creates a new process by running a given program. This is usually given at the start of the script to begin the process. Examples given earlier were spawn ssh user@host or spawn ftp host. You are starting up (connecting to) the process you want to interact with.
Output that gets sent to stdout. This is used for sending message to the screen as the script runs. It is great for user feedback, banners, and for generating error messages.
This will give control of the current process over to the user for interaction. Great if the script can get a person to a certain point and then they have to take over. When you get to the point you want to interact with just put in the word "interact".
By default all process output shows up on stdout (your screen). To stop this you can set log_user to 0 log_user 0 at the top of your script. To turn things back on just set it back to "log_user 1" or remove the line.
This is essentially the Expect debug log mode. Turn this on by setting this to 1 like exp_internal 1. It will show you everything expect sees and how it is trying to match it. This is invaluable for when you think your script should be working, but it is not.
Set is just how to set variables in Tcl and thus Expect. Things like setting the global timeout value from 10 seconds to 20 with set timeout 20. Another would be grabbing a username from the command line of the expect script and setting it to a variable set username [lindex $argv 0].
force_conservative parameter makes expect script to pause for one tenth of a second before sending each character. It is done so your shell will not ignore characters that came to quickly.
set send_slow {10 .001} will send characters with 1 millisecond pause in between each 10 characters sent
Closes the connection to the current process.

Scripting and TCL for Shell programmers


# full path with the script name can use also $argv0 variable
set PROGRAM [ dict get [ info frame 0 ] file ]
set DIRNAME [ file dirname $PROGRAM ]
send_user $PROGRAM\n $DIRNAME\n