expect-lite.proj/0000755000076400007640000000000012012310221014456 5ustar cvmillercvmillerexpect-lite.proj/COPYING0000644000076400007640000000303012564335303015531 0ustar cvmillercvmillerCopyright (c) 2008-2015, Craig Miller Copyright (c) 2005-2007, Freescale Semiconductor, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Freescale Semiconductor nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. expect-lite.proj/install.sh0000755000076400007640000001550012564335303016510 0ustar cvmillercvmiller#!/bin/bash # # Script to install expect-lite from tar file # # # by Craig Miller 5 December 2010 # # 6 May 2011 - fixed install non-privileged user # # 21 Aug 2011 - added configure only option, just configures user # # 11 Aug 2012 - added configure as non-privilaged user # # 5 Jan 2013 - fixed NFS mounted home install issues # function usage { echo "usage: $0 [-p install_location_prefix] [-R] [-c]" echo " $0 - Used install expect-lite and configure ssh, and bashrc " echo " e.g. $0 " echo " " echo " -p installation prefix" echo " -c configure only, configures ssh, and bashrc" echo " -R Remove installation" echo " " echo " By Craig Miller - Installer Version: $VERSION" exit 1 } # Script Defaults numopts=0 VERSION=1.1 SSH_HOME=$HOME/.ssh PREFIX="" # Dirs are defined as relative, fixed later if absolute BIN_DIR=/bin DOC_DIR=/doc/expect-lite MAN_DIR=/man/man1 TOOLS_DIR=Tools BASHRC=$HOME/.bashrc ELRC=$HOME/.expect-literc START_PWD=$PWD OPTS=$* # Get options off of command line while getopts "vVhRp:c" options; do case $options in V ) show_version=TRUE let numopts+=1;; v ) show_version=TRUE let numopts+=1;; p ) PREFIX=$OPTARG let numopts+=2;; h ) usage;; R ) remove=TRUE let numopts+=1;; c ) configure_only=TRUE let numopts+=1;; \? ) usage # show usage with flag and no value exit 1;; * ) usage # show usage with unknown flag exit 1;; esac done # remove the options as cli arguments shift $numopts # check that there are no arguments left to process if [ $# -ne 0 ]; then usage exit 1 fi if [ $show_version ]; then usage exit 1 fi # OS detection Linux|Darwin|CYGWIN OS=$(uname -s | grep CYGWIN) # do the following for non-CYGWIN OSs if [ "$OS" == "" ] && [ "$PREFIX" == "" ] && [ ! $configure_only ]; then MYUID=$(id -u) if [ $MYUID -ne 0 ]; then echo "===================" echo "Please use: sudo $0 $OPTS" echo "===================" usage exit 1 fi fi function installit { # pass in file to be installed, location and step number echo "$3) ===================" echo " Installing $1 in $2" mkdir -p $2 2> /dev/null if [ $? -ne 0 ]; then echo "Ack! No write permissions to:$2!" echo "Sheepishly giving up and Quiting..." exit 1 fi cp -R $1 $2 chmod 755 $2/$1 } function removeall { # blindly removes installation echo "===================" echo "Removing Expect-lite" rm -rf $PREFIX$BIN_DIR/expect-lite rm -rf $PREFIX$DOC_DIR rm -rf $PREFIX$MAN_DIR/expect-lite.1.gz # restore old version of expect-lite (if present) if [ -e $PREFIX/$BIN_DIR/expect-lite.old ]; then mv -f $PREFIX$BIN_DIR/expect-lite.old $PREFIX$BIN_DIR/expect-lite fi # restore bashrc if [ "$USER" == "root" ]; then BASHRC=/home/$SUDO_USER/.bashrc ELRC=/home/$SUDO_USER/.expect-literc fi mod_bash=$(grep expect-literc $BASHRC) if [ "$mod_bash" != "" ]; then # remove source line in bashrc echo "updating bashrc" if [ "$USER" == "root" ]; then sudo -u $SUDO_USER sed -i -e "s;source $ELRC;;" $BASHRC else sed -i -e "s;source $ELRC;;" $BASHRC fi fi echo "Done." echo "===================" } #======== Actual work performed by script ============ # fix up prefixes if no prefix defined if [ "$PREFIX" == "" ]; then # set up "standard" paths BIN_DIR=/usr$BIN_DIR DOC_DIR=/usr/share$DOC_DIR MAN_DIR=/usr/share$MAN_DIR fi # un-install if '-R' is used if [ $remove ]; then removeall exit fi new_ver=$(grep "variable version" ./expect-lite | cut -d " " -f 3) echo "=======================================" echo "Installing expect-lite version $new_ver" #check if expect is installed in standard location if [ ! -e /usr/bin/expect ]; then echo "0) ===================" echo " ACK! expect is NOT installed" echo " Please install expect first:" echo " sudo yum install expect" echo " sudo apt-get install expect" echo " or use cygwin setup to install expect" echo "Exiting...." exit 1 fi # don't move old version expect-lite if just configure only if [ $configure_only ]; then #check if expect-lite is installed if [ -e $PREFIX/usr/bin/expect-lite ]; then existing_ver=$(grep "set version" $PREFIX$BIN_DIR/expect-lite | cut -d " " -f 3) echo "0) ===================" echo " expect-lite already installed, good." else echo "0) ===================" echo " expect-lite NOT installed" echo " Please run installer with install option. Exiting..." exit 1 fi else #check if expect-lite is installed if [ -e $PREFIX/usr/bin/expect-lite ]; then existing_ver=$(grep "set version" $PREFIX$BIN_DIR/expect-lite | cut -d " " -f 3) echo "0) ===================" echo " ACK! expect-lite already installed" echo " Preservering older version $existing_ver to expect-lite.old" # back up older version mv $PREFIX/usr/bin/expect-lite $PREFIX/usr/bin/expect-lite.old fi fi # Actual Install. skip if configure only if [ $configure_only ]; then echo "1,2,3) ===================" echo " Configuration Only selected, skipping install steps 1,2,3 " else # start actual install - Steps 1,2,3 installit expect-lite $PREFIX$BIN_DIR "1" installit examples $PREFIX$DOC_DIR "2" cd man installit expect-lite.1.gz $PREFIX$MAN_DIR "3" cd - > /dev/null cd $START_PWD fi # run configure section as non-privilaged user if [ "$USER" == "root" ]; then echo "SU) ===================" echo " Calling install script as non-privilaged user $SUDO_USER for configuration" sudo -u $SUDO_USER $SUDO_COMMAND -c echo "=======================================" echo "SU) Installation Complete!" echo "=======================================" exit fi # test if bashrc needs mod: Step 4 mod_bash=$(grep expect-literc $BASHRC) if [ "$mod_bash" == "" ]; then echo "4) ===================" echo " Creating $HOME/.expect-literc with expect-lite defaults and " echo " Updating $HOME/.bashrc file " # create expect-literc cp bashrc $ELRC echo "source $ELRC" >> $BASHRC # Step 5 #check if sshd is running - if so, then configure expect-lite to use ssh keys sshd_running=$(ps -e | grep sshd | wc -l) if [ $sshd_running -gt 0 ]; then echo "5) ===================" echo " Configuring .expect-literc for SSH keys" # enable remote_host and connect_method sed -i -e 's;#export EL_REMOTE_HOST;export EL_REMOTE_HOST;' $ELRC sed -i -e 's;export EL_CONNECT_METHOD=none;export EL_CONNECT_METHOD=ssh_key;' $ELRC echo " ===================" echo " be sure to 'source ~/.bashrc' to have changes take effect" fi fi # do the following for non-CYGWIN OSs if [ "$OS" == "" ]; then #check if ssh keys already exist if [ ! -e $SSH_HOME/id_rsa.pub ]; then echo "===================" echo "Creating ssh keys as user: $USER" #su $SUDO_USER -c $TOOLS_DIR/setup_local_ssh.sh $TOOLS_DIR/setup_local_ssh.sh fi fi # Pau! if [ "$SUDO_USER" != "root" ]; then echo "=======================================" echo "Installation Complete!" echo "=======================================" fi expect-lite.proj/ChangeLog0000644000076400007640000003410112564335303016253 0ustar cvmillercvmiller All changes by Craig Miller cvmiller at gmail dot com Released 15 August 2015 v4.9.0 Added Native Sleep support (finally!) Use colon and number to indicate sleep duration :5.5 Supports mili-second resolution Prints progress "dots" while sleeping Sleeping: ....+....10. Added progress "dots" to expect lines (<, <<, ~<) Disable with *NOINFO Released 31 May 2015 v4.8.1 Minor fixes Unpaired user defined help ';;;' caused crash Variable names can now start with underscore e.g. $_myvar Added example for using tcl_functions.inc, mark_time and show_time Released 15 January 2015 v4.8.0 Expect-lite is 10 years old! Fixed fuzzy-expect bug if looking for '0' Fixed *SHOW VARS constant display (was ragged) Fixed include file, passing constant values with spaces Added IDE debug command: SHOW ENV Displays expect-lite flags (e.g. *DEBUG), counters e.g. *INFINITE_LOOP, fuzzy range, Env Vars Improved expect '<' wait mechanism interaction with IDE Added unset variable e.g. $var= Added *TERM N - exit with retun code N (0-255) Released 22 July 2014 v4.7.2 Added Directives *DVPROMPT, *NODVPROMPT, which control Dynamic Variable capture method. *DVPROMPT (default) requires a trailing prompt. (user request) Added include file home '~' expansion e.g. ~~fred/include.inc (user request) Fixed infinite loop bug in fuzzy expect code Fixed last comment line not printed when last line of file Released 1 June 2014 v4.7.1 Fixed while loop comparison if first value was blank Equal/not-equal comparisons are allowed to have blanks Less/Greater than comparisons are not allowed to have have blank values Fixed bug when $var ended in semicolon e.g. $var; Fixed IDE when typing a line which ended in semicolon Fixed CLI with no script and *INTERACT, now exits cleaner Added/Updated examples in examples directory Released 20 April 2014 v4.7.0 Added fuzzy expect ~< Permitting approximate values to be expected e.g. >uptime ~-v display Improved speed EL_REMOTE_HOST=none (default), by shortening delays Released 19 November 2013 v4.6.2 Added env var EL_SHELL for shell to start when connect_method=none Fixed *LOGAPPEND with no file name (now it appends to default name) Fixed *TIMESTAMP to print to *LOG file Fixed CLI directives *INFO, *WARN, *EXP_INFO, *DEBUG to override script values Fixed CLI processing to not overwrite *LOG when using -h (help) Removed EL_LIBRARY mode automatically skipping include files Added *NOINCLUDE to provide backward compatibility for library mode Fixed string math functions concat - now spaces are not required e.g. =$var1+$var2 search/replace - searching for minus now fixed =$var/-/z/ Released 23 July 2013 v4.6.1 (foreach release) Updated foreach to normalize lists (removing extra spaces) when executing loop Improved login prompt detection with EL_CONNECTION_METHOD=none Removed unessecary 5 second delay Added code to remove of \r\n from *INTERACT pasted text This is to improve windows copy/paste into putty Released 28 May 2013 v4.6.0 (foreach release) Added foreach loop using code blocks e.g. $list=abc def ghi [ $x=$list >echo $x ] Added string math - search/replace options on strings Supports concat, removal, search/replace e.g. $string=mylong2013string =$string + may yields: mylong2013stringmay =$string - long yields: my2013string =$string/(\w+)(\d+)/\2\1/ yields:: 2013mylongstring =$string//3stri/o/ yields: mylong201ong Improved ssh login sequence, answering yes to login question automatically removed ssh "-o StrictHostKeyChecking=no" option ssh has very good support for ssh options on ~/.ssh/config Fixed bug when running expect-lite in screen (TERM=screen) Released 10 March 2013 v4.5.0 (dog bone release) Added else code block ]::[ e.g. ?if this == $that ? [ do this ]::[ else do that ] Added Environment Var EL_INFINITE_LOOP Shortened expect-lite help, removed old style c=command_script old style still accepted on CLI Added experimental web front end - el_run.php Released 27 January 2013 v4.4.1 Fixed nasty bug when using *LOG on CLI Released 21 January 2013 v4.4.0 Added native logging to file with directives *LOG *NOLOG *LOGAPPEND Includes new Env Var: EL_LOG_EXT to control log file extesion (default=".log") CLI *LOG or *LOG overides *LOG inside script Updated ssh login to always accept host key Improved install.sh for NFS mounted home drives expect-lite turns 8! Released 4 December 2012 v4.3.3 Fixed "send" bug "bad flag -1" Fixed dyn var capture when "=" are present e.g. +$var=(\d) = STRING: Fixed single number expect, if number was not on a line by itself Added warning when using redirection and user presses ^\: Fixed dyn var capture when "=" are present e.g. +$var=(\d) = STRING Released 12 August 2012 v4.3.2 Small bug fixes Ubuntu BUG #994386 - login send incorrect env setup command Fixed while loop test blank (indefined) variable Fixed infinite loop counter (was still counting too many) Fixed install.sh to configure as unprivilaged use (fix for NFS mounted home dir) Released expect-lite blog - http://expect-lite.blogspot.ca Released 27 June 2012 v4.3.1 User defined help (run your script with a -h) Pass include files parameters (e.g. ~login.inc user=root) Lots of small bug fixes Fixed path bug with include files Fixed ssh (no key) login prompt detection Fixed *INFINITE_LOOP bug, would double/triple count down Fixed to work with older versions of expect (older than 5.44.x, such as cygwin, and old linux installations) Fixed CLI -v,-vv,-vvv override of logging (*INFO, *WARN, *DEBUG) Validate EL_CONNECT_METHOD at startup (default=none) Released 24 April 2012 v4.3.0 Added "User Defined Help", see with -h or --help e.g. ;;; start of help This script configures all routers ;;; copyright 2012 Added passing arguments to include files e.g. ~login.inc user=root Passed arguments var=value scope is only inside the include file Added ##Include Result: FAILED: Added directive *NOINTERACT to ignore breakpoints (*INTERACT) Useful for quick regression scripts Added include filename check at startup ensure include files are available before executing script Re-added *PASS as pseudonym for *TERM This behaviour will be improved later Released 13 February 2012 v4.2.2 Fixed _buf(stack) crash in library mode only Updated if-else to handle ipv6 addresses with double colons ipv6 addr is defined at [0-9a-f:] expect-lite should now fully support IPv6 Released 13 December 2011 v4.2.1 Fixed jump to label in IDE single step e.g. ?if 1==1? %TEST Cleaned up IDE paste (first line pasted must not be indented) Fixed buffer read - more specific about lines read into buffer Fixed buffer read problem with lines ending in backslash \ Released 11 October 2011 v4.2.0 Added Code Blocks, grouping lines of script for if statements and while loops Added while loops via code blocks, e.g. [ $i < $n ] While loops have infinite loop protection (defaults to 5000) Code Blocks can be pasted into IDE (with expect version 5.42 or later) Added constant values can have spaces on CLI - feature request from Michel Desjardins e.g. var="value and spaces" Cygwin has been tested, however expect 5.26 (from 2003) does not support IDE paste Working on submitting a newer version to Cygwin repository Fixed var increment with spaces at end of var e.g. +$var Released 23 August 2011 v4.1.2 Fixed @n (n=number) to set timeout value from IDE (problem with ssh user@192.168...) Fixed *FORK display, when "session" is part of the session name Added conditional test for undefined varibles if undef var, treat var as "" e.g. ?if $undef_var == $blank ? or ?if $undef_var == ? Updated installer with "configure only" option, just configures user Released 26 June 2011 v4.1.1 Implemented reverse search of labels, allowing non-unique labels for looping Fixed *FAIL to work with *NOFAIL, rather than terminating immediately Added @n (n=number) to set timeout value from IDE Released 12 April v4.1.0 Bug fixes Fixed *FORK default bug (wasn't switching back to default) Fixed IDE Step, when *FORK command is step, session didn't change Fixed bug in fail script handling, script would not fail Fixed bug in parse_var, added pipe (|) to "end of var" list Added new Library-mode: expect-lite now can be a TCL package API now permits calling expect-lite interpreter from inside TCL See Docs and example script test_el_lib.tcl Released 22 Feb 2011 v4.0.3 Bug fixes Fixed *NOFAIL inside IDE, command didn't persist after continuing script Fixed *FORK inside IDE, was not returning to correct session upon Continuing script (+++) Fixed terminal-type to include xterm-color Fixed bug in Bad Time Out Value (found by Tajas Petal) Added new logging directive Added *TIMESTAMP ISO|YMD|DMY|MDY & *NOTIMESTAMP (idea from Kevin Broch ) ISO is default timestamp format Added expect-lite-lib ground work, not ready for release yet Released 21 Dec 2010 v4.0.2 Minor change to debugger copy/paste to permit absolute paths First release of tarball installer Released 26 Oct 2010 v4.0.1 Reworked buffers completely (now global array) Added Integrated Debugger with breakpoint, step/skip, copy/paste IDE: Help Key Action ---- ------ s Step k sKip next step c Continue v show Vars 0to9 Show N next lines of script -1to-9 Show N previous lines of script ctrl+D Quit & Exit expect-lite h this Help Added directive *INFINITE_LOOP N - changes infinite loop protection value Added any *DIRECTIVE on the CLI (not **SHELL) Added *NOFAIL directive - script runs to completion Added RED old expect version warning, now requires minimum 5.42 Compiled cygwin version of expect 5.45, available on website Added Env Var support: EL_CONNECT_METHOD, EL_CONNECT_USER, EL_CONNECT_ PASS, EL_DELAY_WAIT_FOR_HOST Add $arg0 to v *SHOW VARs commands Added self test scripts for IDE Native method to make scripts executable #!/usr/bin/env expect-lite Created bashrc as example for setting env vars to customize expect-lite Updated Documentation, including cygwin page Released 16 Sept 2010 v3.7.1 release of 3.7.1d7 updated Man page Updated 10 Sept 2010 v3.7.1d7 Fixed ^\ during a pipe to 'tee' - would give call trace Now expect-lite just exits with error Changed -w to -V to show *EXP_INFO Updated 26 August 2010 v3.7.1d4 Fixed errant color issues (when TERM=tty) Added *EXP_INFO, *NOEXP_INFO - shows expected lines in stdout Added CLI argument -w to turn on *EXP_INFO Added custom color to comment lines, if first word is recognized color e.g. ;red This comment is red Added *PASS - synonym for *TERM Released 2 August 2010 v3.7.0 Release of 3.7.0d5 as 3.7.0 Updated 30 July 2010 v3.7.0d5 Added *NOCOLOR directive Added *EOLS LF|CRLF directive Sends \n or \r\n Made fork context to hold eols per session Cleaned up *INTERACT - passes *FORK down with other commands Updated 28 July 2010 v3.6.4d2 Added path for telnet - fixes cygwin/windows wrong telnet issue Added ANSI color to INFO,WARN,ERR Can assign color=none to all Added TERM detection for xterm, ansi, vt100, vt220 Released 19 July 2010 v3.6.3 Added support for -r -c

Using expect-lite with Cygwin

Althought expect-lite was initially created for the Linux environment, there are many users of expect-lite using windows and cygwin. Version 4.0.1, has been tested extensively on cygwin.

Unfortunately, the current version of expect, used by expect-lite, in cygwin is quite old (2003).

NOTE (June 2012): versions 4.2.0 thru 4.30 will not work with the old version of expect in cygwin. This has been fixed in 4.3.1

Limitations of using the old cygwin expect from 2003 

The Powerful new Debugger in expect-lite is using underlying features of expect which are just not available in the 2003 version. Although expect-lite script should execute without problem, some of the newer cool debugger features will not work correctly.

The limitations in the Debugger are:
  • Copy/Paste expect-lites into the debugger - not supported. A warning will be printed when entering the Debugger
  • Debugger commands: must use back-quote ` rather than the escape key

There is a newer version of expect available

I have compiled the CVS version of expect 5.45 for cygwin. A tar file is available which includes the expect binary, and required libraries.

Download the newer version of expect, and unleash the full potential of expect-lite on your cygwin system.

To install the tarball, untar from the root
  • cd /
  • tar xvzf cygwin_expect_5_45.tar.gz
To verify new version type: expect -v

If anyone has experience creating Cygwin packages, please drop me a note, I would like to update the version expect in the Cygwin repository.


27 June 2012
http://expect-lite.sourceforge.net/

this document for version 4.3.1 and above

expect-lite.proj/Docs/expect-lite_doc.html0000644000076400007640000036535512562370421021347 0ustar cvmillercvmiller expect-lite Doc

greater than

expect-lite


Automation for the rest of us



List of Features

Expect-lite has many features which make expect-style script writing easy.

Easy of Use
Variables
  • Static and Dynamic Variables with math functions and pseudo arrays
    • String Math allows manipulation of strings: search/replace, +, - 
  • Constants, passed on the command line or set as environment variables, which override variables in the script. Powerful feature allows any variable to be passed on the command line
  • Leverages Bash shell passing unknown variables to the shell
Programmatic
Advanced
Debugging



Introduction

Automatic Login

expect-lite was born into a multi-host environment, and therefore there was the early requirement to remote login to a host (usually a Linux machine) allocated by a sharing facility such as the commercial package, LSF. Therefore, a remote host must be specified on the command line where the script will wake up and begin executing.

Three methods of remote login are supported:
  • telnet
  • ssh with password
  • ssh with keys (no password)
ssh with keys is the preferred method, since no password is required, however this requires some environment setup before hand.

Even when no remote host is required, it is best to log into the localhost, since the underlying Expect has problems with synchronization (between send and expect strings) when a remote host is not specified. The provided shell script 'setup_local_ssh.sh' will setup the localhost with ssh keys. It is only necessary to run it once:
./setup_local_ssh.sh
Based on the command line arguments passed, expect-lite will do the following:
  • Automatically log into the remote host via telnet or ssh (if ssh keys have been previously setup)
  • Change directory to the passed directory (if included)

In the following example of expect-lite:
./expect-lite remote_host=remote-host-018 cmd_file=basic_ping_test.elt user_dir=/etc
Or the shorter version
./expect-lite r=remote-host-018 c=basic_ping_test.elt d=/etc
Or the shorter version which is more linux like
./expect-lite -r remote-host-018 -c basic_ping_test.elt -d /etc

expect-lite will log into remote-host-018, change directory to /etc/ and begin to send commands from basic_ping_test.elt to the remote-host. The parameters of remote_host and cmd_file are required, as expect-lite must know what host to log into, and what script (aka command file) to run.

Environment Variables

The following environment variables permit the customization of expect-lite without having to edit the expect-lite script itself. It is recommended that commonly used environment variables be placed in the .bashrc or .cshrc file where they will be automatically set upon login.
Env Var
Description
EL_REMOTE_HOST
Name or IP of remote host
EL_CMD_FILE Name of expect-lite script to run
EL_USER_DIR Change to this directory upon login before executing script
EL_CONNECT_METHOD The method expect-lite uses to connect to remote host. Valid options are: none|telnet|ssh|ssh_key
Default is none
EL_CONNECT_USER User name to use for login on remote host (telnet|ssh)
EL_CONNECT_PASS Password to use for login on remote host (telnet|ssh)
EL_LOG_EXT
The log file name extension string, default=".log" (see *LOG)
EL_INFINITE_LOOP=N
Infinite Loop protection value, set N to user's default value (default=5000) (see *INFINITE_LOOP)
EL_DELAY_WAIT_FOR_HOST Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture. 100 ms is a good value for a local LAN, 200 ms if running across high speed internet
EL_SHELL
Start this shell (default=bash) when using EL_CONNECT_METHOD=none
EL_DYN_VAR_PROMPT
Set the Dynamic Variable capture method to require a prompt (default=1). Disable by setting to 0.
EL_* Any other shell environment variables starting with EL_ will become constants

Special Character Sequences

Although basic expect-lite scripts can be created by simply cutting and pasting text from a terminal window into a script, and adding '>' '<' characters, such as:
>pwd
</home/user
Much more functionality is available. expect-lite interprets punctuation characters at the beginning of each line in the script:
Char
Action
>
send string to the remote host
>>
send string to remote host, without waiting for prompt (see implementation details)
<
string/regex MUST be received from the remote host in the alloted timeout or the script will FAIL! (see test failure)
<< literal string MUST be received (similar to '<' without regex evaluation)
-<
if string/regex IS received from the remote host the script will FAIL! (see Not Expect)
~<
expect an approximate number (see Fuzzy Expect)
#
used to indicate comment lines, and have no effect
;
are also used to indicate comment lines, but are printed to stdout (for logging)
;<colour>
add custom colour comment lines, colour may be blue,  ltblue,  gray,  ltgray,  cyan,  black, pink, purple, red, green, yellow
;;
similar to above, but no extra newlines are printed (useful for printing script help)
;;;
Marks the beginning and end of user defined script help (see script help)
@num
changes the expect timeout to num of seconds
:num
sleeps for num seconds. Mili-seconds also supported e.g.  :1.005 is 1005 mili-seconds (see sleep)
$var=
static variable assignment at script invocation (see variables for details)
+$var=
dynamic variable assignment  (see variables)
+$var increment value of $var by 1 decimal (see repeat loop)
-$var decrement value of $var by 1 decimal
=$var
math functions, perform bitwise and arithmetic operations:  << >> & | ^ * / % + - (see math functions)
=$string
string math functions, maniuplate strings: + - / // (see string math functions)
!
indicates an embedded expect line (see embedded expect)
?
c-style if/then/else in the format ?cond?action::else_action (see conditionals and code blocks)
[ <test>
]
while loop (see code blocks)
[ $var=list
]
foreach loop (see code blocks)
%
label - used for jumping to labels (see conditionals)
~filename var=value
includes a expect-lite automation file, useful for creation of common variable files, or 'subprograms/subroutines' (see include files)

In addition to the above special characters, blank lines or lines starting with any non-special character are allowed to make the script file more readable.

Sometimes control characters must be sent. Currently all control characters are supported (from ^@ to ^\):
  • ^C or break, when it is desired to stop a running program e.g. >^C or >>^C
  • ^] or escape from telnet, e.g. >^] This will bring the script to the telnet prompt, then use: >quit
  • ^<any char> will send a control character to the remote-host, such as ^D to logout
Control characters must be the first two characters on the line (e.g.[^][A-Z]). The sequence of ^C anywhere else in the line will not be interpreted as a control-C, but rather the two characters '^' 'C'.

Lastly, any line beginning with an asterisk '*' will be interpreted as an expect-lite directive. Directives change the behaviour of expect-lite.

Expect-lite Directives
*~filename Include a fail script, which expect-lite runs only if the main script fails (see fail script)
*/prompt/
Set a user defined prompt (see user defined prompt)
*TERM <N>
Immediately terminates script, but returns 0 (pass), or if N is specified returns the value of N (0..255)  (see stopping execution early)
*FAIL
Immediately fails script, and returns 1 (fail) (see stopping execution early)
*NOFAIL Script will run to completion, and returns 1, if failure occurred during execution, or 0, if pass
*NOINTERACT
Will ignore breakpoints (*INTERACT), good for regression testing (see directives)
**SHELL=<shell>
Configuration directive which sets the shell immediately after automatic login to remote host (see setting the shell)
*INTERACT
Sets a breakpoint and places user in interact mode, which pauses the script and turns control of the keyboard over to the user (see Tips & Techniques: Interact)
*FORK <session> Multiple session support. Directs expect-lite to open a new session and spawns a newshell (see multiple sessions)
*SHOW VARS
Debug information, displays all expect-lite variables. Can be used in interact mode.
*EOLS LF
*EOLS CRLF
Controls end of line sequence sent to remote host, either line feed, or carriage return & line feed.
*DVPROMPT
*NODVPROMPT
Enable/disable the Dynamic Variable capture method to require a prompt (default=*DVPROMPT).  (see Dynamic Variable capture method)
*INFINITE_LOOP <N>
Sets/resets the infinite loop protection value, which is a total count of all loops in script. Default is 5000
*NOINCLUDE
Ignore include files (was default behavour in library mode)

Logging Directives
*LOG
*NOLOG
Enable/disable logging to a file. Will create file <script_name>.log (same as $arg0.log) if no path/file_name is supplied.(see managing logging)
*LOG  <file_name>
*LOGAPPEND <file_name>
Enable  logging to a user specified path/file_name. When invoked on the CLI, the specified file_name must end in ".log" to  avoid ambiguity
*INFO
*NOINFO
Enable/disable informational messages
*WARN
*NOWARN
Enable/disable warning messages
*DEBUG
*NODEBUG
Enable/disable debug messages
*NOCOLOR Disables color output, best when logging output
*TIMESTAMP <ISO|YMD|DMY|MDY> Prints Date and Timestamp for each command sent, ISO is default
*NOTIMESTAMP Disables timestamp printing

IPv6 Support

expect-lite is an application, and will use communications protocols such as telnet and ssh to connect to a remote host. If telnet or ssh is IPv6 enabled, then expect-lite can/will use it.

However, it may be important to include IPv6 addresses in expect-lite scripts. expect-lite now fully supports IPv6 addresses including short hand notation with double colons, e.g. 2001:db8::dead

Care has been taken to have expect-lite do the right thing with IPv6 addresses, however, it may be necessary to be more explicit when using conditionals (if/then/else), see conditionals and IPv6.

General Tips for writing scripts

Here are some simple tips when script writing:
  • Use reasonable timeouts, if 30 seconds is needed to get a response, set the timeout at 45 or 60 seconds, not 600.
    • There is no cost to changing the timeout, timeout values can also be variables
  • Beware of expect-lite using regex, when creating lines like: <0.005 secs (5 micro secs)
    • The parentheses is used by the regex engine, instead escape these characters: <0.005 secs \(5 micro secs\) (see Use of Regex in expect-lite)
    • or use '<<' which does not use regex, and does not require escaping: <<0.005 secs (5 micro secs) (see using non-regex evaluation)
  • Use the expect character '<' or '<<' often. Check for valid results when possible. A script which expects nothing will never fail! (see Test Failure)
  • Use printable comments ';'  and ';;' often. Think of it as writing a note to oneself, it will make reading log files much easier. As of version 3.7.0 printable comments will be coloured blue (this is user configurable).
  • Variable assignments use no spaces e.g. $var=value. Note no spaces around the equals sign, this permits leading spaces in the value such as $var=  myvalue

Debugging Expect-lite Scripts

Expect-lite was written to permit quick and easy automation of repetitive tasks. However, sometimes a little additional debugging is required.

Instant-Interact (as of version 3.5.0) or instant breakpoint, provides instant debugging assistance. Pressing ^\ (control+backslash) will force expect-lite to drop into interact mode, a mode which turns control of the keyboard over to the user, so that one may type directly to the process on the remote host. To return to the script, type '+++' (three pluses). During interactive mode, timeouts do not apply, *NOFAIL is automatically enabled, and the script will wait indefinitely for the user to exit this debugging mode. Switching between multiple sessions (see *FORK) is possible via typing the *FORK command in interact mode (see *FORK debugging).

Additionally, the interact mode (or Integrated Debugger Environment) performs three primary functions: 1) connecting the user to the remote host or device under test, 2) monitoring special commands prefaced with the escape key for stepping, and other functions, and 3) the debugger will allow expect-lite script lines to be executed by either typing directly or pasting them into the IDE.

See the Tips and Techniques Guide for additional expect-lite script debugging information.




Reference

Use of Regex in expect-lite

Support of regular expressions in expect-lite are limited by:
  1. Support of regex in standard expect (e.g. including anchors, char-classes and repeats)
  2. Support of regex meta characters (e.g. \t \n \d)
  3. Expect-lite only evaluates lines using regex which begin with '<'  '-<'  '~<' and '+' (dynamic variables)
The following is a table of supported meta-characters, and repeats

Meta-Char
Description
\d
any digit
\D
any non-digit
\w
any word char
\W
any non-word char
\s
any white space
\S
any non-white space
\t
tab
\r
return
\n
new line
.
any character
|
regex OR
Repeats

?
0 or 1
*
0 or more
+
1 or more


As an example, a range of numbers is valid for an IP address. The following would permit the last octet of the IP address to be 2 digits, but not 3.
> /sbin/ifconfig eth0
<inet addr:10\.29\.200\.\d\d\s
The periods are preceded by a backslash to indicate to regex that a period must be returned rather than the regex dot '.' which indicates any character. The \d indicates any single digit.

Because regex is always enabled for expected results, some 'escaping' of characters must be done when using '<'. The following characters must be escaped with a backslash to convey their literal meaning:

Example
Escaped
Character
(abc) \(abc\) parenthesis
[abc]
\[abc\] 
square brackets
\
\\
backslash
. \.
period
$ \$
dollar sign
+ \+ plus
* \* asterisk (or star)
| \| pipe

Regex is a very powerful syntax unto itself, and one can create quite complex regex strings. There is an excellent regex cheat sheet created by David Child, which is very helpful. That said, one does not need to be a regex expert to use expect-lite, it is possible to use regex in a very basic way, see examples for more info.

Using << for non-regex evaluation

There are times when the use of regex is not desired, or 'escaping' characters is burdensome. As of version 3.6.0, expect lines can begin with '<<' which will not use regex, but rather literal evaluation of expected results. 

Handling HTML/XML Tags in expect lines
The << may cause a backward compatibility problem, if the script was expecting an HTML tag, such as
>grep body my_html_file.html
<<body.+>
In the above example, the script is expecting a body tag with 1 or more characters between body and the closing greater-than of the tag. However the new feature will not interpret this line as regex, but rather interpret the beginning of the line as <<, and evaluate it as a literal. The method to force expect-lite to evaluate the line as regex, is to change the line is slightly:
>grep body my_html_file.html
<[<]body.+>
By making the first expected character as a regex character class, it signals to expect-lite that this line should be evaluated as regex, rather than a literal.

Using Variables

Expect-lite supports two types of variables:
  • Static, which are bound at invocation
  • Dynamic, which are bound during execution of the script
Lines starting with a '$' indicate variables which are assigned and set at script invocation, and therefore are static. In expect-lite variable names will always be preceded with a '$'. Variable names are limited to the following set of characters [A-Za-z0-9_]. When making variable assignments, there must NOT be a space between the variable name and the equals sign:
$myvar=myvalue
There are times when it is necessary to unassign or unset a variable, because, it is desired to have the variable be dereferenced by the underlying shell (see bash shell), or that pseudo- arrays are being used (see pseudo-arrays). To unassign a variable (v4.8.0), merely assign it an empty value.
$myvar=

Dynamic Variables

Sometimes it is desirable to bind a variable during the execution of the script. Dynamic variables fill this need by utilizing Expect's built-in regex capture mechanism. Only the portion of the match inside the parenthesis will be bound to the variable. The format of the line is as follows:
+$somevar=text that is not put into the var (text which is put into the var)

Dynamic Variables are always bound to Expect output, meaning text which is returned from the remote host. Therefore something must be sent to the remote host, before text can be returned. A typical usage would be:
> command
+$myvar=command output (capture value) more command output

If the value of the var is successfully captured then expect-lite will print:
Assigned Var:somevar=sometext which is put into the var

If, however the dynamic var is not successfully captured, expect-lite will print:
Assigned Var:somevar=__NO_STRING_CAPTURED__
Avoid using an overly general capture as it will tend to capture too much, or the wrong info. e.g:
> command
+$myvar=\n(.*)
Instead use a specific capture when possible. When capturing the current directory, the current directory will always start with '/', and the path will be made up of a known character set:
> echo $PWD
+$mypwd=\n(/[a-zA-Z0-9/\-_]+)

Expect-lite will print to stdout the value of the assigned variable, assisting the script writer in understanding the value that is bound to the variable during runtime. The value of "__NO_STRING_CAPTURED__" indicates that the regex pattern used did not match the return data. It is best to start using this feature with short scripts targeted at capturing the desired information. Examples can be found in the example section of this document.

Math Functions with Variables

There are times when writing a script it may be necessary to perform arithmetic or bitwise operations, also known as math functions. Expect-lite inherits expect/tcl math functions and natively supports math/bitwise operations on a variable, using the following slightly odd notation:
$myvar=1
=$myvar + 2 * 10
In the above example, 2 will be multiplied by 10 and added to value of $myvar (1). The result of 21 will be placed in $myvar, overwriting the previous value. Since multiplication has a higher precedence than addition, (2 * 10) will be performed before the addition to $myvar.

Parenthesis may be used to enforce user defined precedence. In the following example, the result will be 23:
$myvar=1
=$myvar + 2 * (10 + 1)

Both bitwise and arithmetic operators are supported with the following precedence (left to right):
bitwise
<< >> & ^ | shift left, shift right, bit and, bit exclusive or, or
arithmetic  * / % + -
multiply, divide, modulo, add, subtract


If $myvar does not exist before the math function, it will be initialized to blank and then math functions will be performed. In the following example the result, $myvar, will be 20:
=$myvar + 2 * 10
However, realistically, only the '+' operator works as expected in the above example. Using other operators will more than likely yield a syntax error:
Warning: Expect-lite: Unable to interpret =$answer1 / 2 * (10 + 1) 
syntax error in expression " / 2 * (10 + 1)": unexpected operator /

Because of the expect/tcl inheritance of math functions, all operations will be performed as integers (or whole numbers) unless a decimal (or real) number is used explicitly. In the following example the result is 2.5:
$five=5
=$myvar + $five / 2.0
However, the following (because of the use of integers) example will have the result of 3:
$five=5
=$myvar + $five / 2

Math functions can be used with static and dynamic variables.

String Math Functions with Variables

With the introduction of version 4.6.0, String Math functions have been added. The functions which enable simple manipulation of strings are:
  • Concatenation using +
  • Removal using -
  • Search and Replace using / or //
In order to use string math functions, the variable must already be defined as a string (think: non-numeric). The following is an example of concatenation:
$mylist=abc,def,hig
$lmnvar=,lmn
=$mylist + $lmnvar
This will result in $mylist being equal to abc,def,hig,lmn

String removal will remove all instances of the substring
$mylist=abc,def,hig
$lmnvar=,def
=$mylist - $lmnvar
The result of $mylist will be abc,hig

Search and Replace

Search and replace is the most powerful of functions and uses the slash '/' operator. The form is as follows:
=$myvar /search/replace/
There is a regex / and non-regex // form.

Regex
=$var /search/replace/
Regex support for search and replace,
includes char class, meta chars, capture
Non-regex =$var //search/replace/
Literal search and replace

The non-regex is straight forward, in the following example, one might want to replace commas with spaces (to be used in foreach loop list):
$mylist=abc,def,hig
=$mylist //,/ /
The result would be: abc def hig

The regex version can do more complex operations such as removal of the subnet for IPv4:
$myip=192.168.0.50
=$myip /\d+\.\d+\.\d+\.(\d+)/\1/
The above example searches for a string of digits, dot, digits, dot, digits, dot, then lastly captures the last set of digits. It then replaces the entire IP address with captured value (using the \1), resulting in $myip equaling 50.


Pseudo Arrays

Expect-lite supports pseudo arrays, which are different from a real array (e.g. item[1], item[2],...). Pseudo arrays are made possible by the fact that variables on the left side of the equals can be dereferenced at assignment time. For example, below, the variable $count will be dereferenced (or resolved) prior to assignment:
$myarray$count=some $value
When placed in a loop with a looping variable of $count, a pseudo array of $myarray1, $myarray2, $myarray3,... will be created. Individual values can be retrieved from the array by using the index (or $count) such as $myarray23.

The pseudo array name (variable + index) must be a valid variable name, in the set of characters (A to Z, a to z, 0 to 9, and underscore) and no spaces.

Constants

Expect-lite Constants are represented as variables which are passed into expect-lite at runtime or retrieved from environment variables starting with EL_. Constants will override any script variable already defined inside the script, are immutable, and cannot be changed. Constants can be used to change the behaviour of the script.

For example, one might invoke the following test as:
./expect-lite remote_host=remote-host-018 cmd_file=basic_ping_test.elt \
user_dir=/etc local_eth=eth2

Inside the script basic_ping_test.txt any reference to $local_eth would be set to eth2, thus allowing the script actions to be changed based on the constant passed at invocation. Constants will override any script variable already defined inside the script.

Shell Variables

Expect-lite allows the use of shell variables, which can be more powerful than the built-in variable mechanism. However shell variables will only be resolved by the shell. For example, assigning current working directory to a shell var:
> PWD=`pwd`
> echo $PWD
However, the following test would fail, since $PWD is a shell variable, not an expect-lite variable:
> PWD=`pwd`
>pwd
< $PWD
Shell variables (or environment variables) must be dereferenced by the shell. Similarly, expect-lite variables must be dereferenced by expect-lite.

It is possible to read a shell variable into an expect-lite variable by using the dynamic variable method:
> echo $PWD
+$mypwd=\n(/[a-zA-Z0-9/\-_]+)

Undefined Variables

Since expect-lite allows the use of shell variables, it is possible that a variable will not be known to expect-lite (but known to the shell). Expect-lite will attempt to dereference all variables, the ones which are not defined remain in variable form (perhaps it is a shell variable). However, it can be useful to test if a variable is an expect-lite variable. As of version 4.1.2, in a conditional (if statement) undefined variables will be automatically defined as blank ( or ""). See conditional for more information.

Environment Variables starting with EL_

When expect-lite starts up it will automatically search the environment variables (aka shell variables), and import any found starting with EL_ as constants. This enables setting environment variables as passwords, or remote hosts.

For example, the environment variable EL_sudopass might be set to "mysecret". In the script, the variable would be used as:
>sudo tcpdump -i eth0
<<[sudo] password
>>$EL_sudopass

Using Conditionals & Labels

Conditional (if/then/else) statements are natively supported in expect-lite. The conditional uses a c-style syntax with a question mark (?) at the beginning of the line, and double colon to indicate the else statement, using the format ?cond?action::else_action

Although spaces are not required around the conditional characters (? and ::), it is recommended for ease of reading. The comparison operators are: '==',  '!=' ,'>=',  '<=',  '>' and '<'. If the compared values can be evaluated as a numbers, then larger and less than will yield expected results. A simple conditional example:
$age=56
? $age >= 55 ? >echo "freedom at 55!" :: > echo "keep working!"
In the above example if $age is larger than or equal to 55 then the action 'echo "freedom at 55!". If $age is less than 55 then the action 'echo "keep working!"' will be sent.

Each action or else_action is as if it began on a separate line. Since in the above example '>' is used (e.g. >echo) the echo line will be sent to the remote host. Any expect-lite action (see Special Characters) can be placed after the second question mark. For example, an include file may be executed based on a conditional:
$platform=ppc
? $platform == i386 ? ~connect_i386.inc :: ~connect_ppc.inc
In order to make log files more understandable, a message will be printed when a conditional is evaluated, such as:
If: expr { "ppc" == "i386" } |then ~connect_i386.inc|else ~connect_ppc.inc|result0
The message prints: what was evaluated (expr { "ppc" == "i386" }),  'then', and 'else' actions, as well as a result (true or false)

IPv6 Addresses

Because IPv6 addresses are quite long, it is a common short hand to represent a long string of zeros with a double colon '::', such as 2001:db8::f00d. The conditional also uses a double colon to signal the else portion of the conditional, so what happens when:
$platform=ppc
? $platform == i386 ? $my_addr=2001:db8::f00d :: $my_addr=2001:db8::feed
Fortunately, as of version 4.2.2, it will be as expected, $my_addr will be set to 2001:db8::feed

If in doubt, be sure to place spaces around the else double colon, as spaces are never allowed in an IPv6 address.

Undefined variables

Undefined variables can be tested in a conditional (as of version 4.1.2). In and only in a conditional, variables unknown to expect-lite are dereferenced as blank. This allows testing if a variable has been defined such as:
$blank=
?if $TEST ==$blank? ; === echo this :: ; === echo that
?if $TEST != ? ; === echo this :: ; === echo that
The first example, is setting a variable to blank and then testing for equality. The second example demonstrates testing inequality with blank. Either conditional will work, and it is a matter of style which one is preferred.


Labels

Conditionals are limited to a single line. Sometimes this is too limiting, as it would be nice to have several commands be executed based on the success of a conditional. To support this, the concept of labels has been introduced. A label is defined as having the first character a '%'. Although the label line itself does nothing, it provides a location to the conditional to Jump To Label. The following is a simple example of using a conditional in conjunction with a label:
$kmodules_inserted=true
? $kmodules_inserted == false ? %SKIP_CHECK_KMODS
>lsmod | grep nfs
<nfsd
<exportfs
<sunrpc
%SKIP_CHECK_KMODS
When a label is the action of a conditional, there is an implied Jump to Label. Lines between the conditional and the label will be skipped. The Jump to Label action is no longer limited to only jumping forward. (see Looping with Conditionals)

Multiple labels with the same name are permitted. For example, a conditional action may be Jump to Label %SKIP. However this is only recommended for looping (as of version 4.1.1 expect-lite searches backwards for labels) Of course it is easier for the script reader if clearer label names are used. Labels may contain spaces, as in this example:
; === Test conditional jump to label
? $jump == true ?%move along, nothing to see
>echo "1"
>echo "2"
>echo "3"
%move along, nothing to see
To assist reading the logs, the action Jump to Label will generate a message to standard out (captured in the log). From the above example, the following would be printed:
Jumping to label:%move along, nothing to see

Looping with Conditionals & Labels

Simple looping is supported by allowing jump to label backwards in the script. The Repeat Loop is the easiest loop to implement:
; ======== Incrementing Loop ========
$max=5
$count=3
%REPEAT_INC_LOOP
>echo $count
# increment variable
+$count
?if $count <= $max ?%REPEAT_INC_LOOP
Because of jump to label default behaviour has been changed in version 4.1.1 to jump backwards, it is no longer important to assign unique looping labels. Non-looping labels, as illustrated in the previous section, must (as of version 4.1.1) be unique.

Also included in the above example is incrementing an expect-lite variable: +$count
This will add 1 to the value of $count. If $count is not an integer, the value of $count will remain unchanged (can't add 1 to a string).

As part of the looping enhancement, there is infinite loop protection. The maximum amount of looping is defined with the directive *INFINITE_LOOP N. This value is decremented with each iteration of all loops for the entire script. Typically this would be in the range of 1000 to 10000 to be safe. For example, if a complex expect-lite script had 4 loops each with 100 iterations, the directive *INFINITE_LOOP should be set larger than 400. As of version 4.5.0, the environment variable EL_INFINITE_LOOP is used to override the default value.

Using Code Blocks with Conditionals, While Loops and Foreach Loops

expect-lite is a line oriented scripting language, but there are times when it is convenient to group lines together. As of version 4.2.0, the grouping of lines can be achieved through code blocks. A quick example using a code block and a conditional:
; === Conditional using code block
? $case == true ? [
>echo "1"
>echo "2"
>echo "3"
]
Conditionals

A code block begins with a [ (left square bracket) and ends with a ] (right square bracket). When used with an if statement, it allows more than one "line" to be executed based on the evaluation of the if statement.

Conditionals with code blocks also support the else construct, such as:
; === Conditional using code block as else statement
? $case == true ? >echo "true" :: [
>echo "false 1"
>echo "false 2"
>echo "false 3"
]
As of version 4.5.0 Code blocks are supported in both the then and the else sections of a conditional:
; === Conditional using code block then and another code block else statement
? $case == true ? [
>echo " 1"
>echo " 2"
>echo " 3"
]::[
; else code block
>echo " 4"
>echo " 5"
>echo " 6"
]
However, using the square brackets on the same line is still not supported, since it appears ambiguous:
; === NOT SUPPORTED Conditional using code block then and else statement
? $case == true ? [ :: [
>echo " 1"
]
Nested code blocks can also be used. In the following example each if statement is using a code block for the then statement, and a non-code block for the else statement:
$test=3
; === nested ifs using code blocks
?if 1 < $test ? [ :: >echo "else 1"
?if 2 < $test ? [ :: >echo "else 2"
>echo "if 2"
]
]

While Loops

Code blocks can also be used for quick looping using an implied while loop construct. In the following example, the expression at the beginning of the code block will be evaluated, if true, the lines inside the code block will be executed. The expression (e.g. $i < 3) will be evaluated each time the code block has completed execution. Once the expression evaluates false (in the example $i is equal to 3), the script will continue on the line after the bottom of the code block. The <test> operators are:
Test
Action
==
equal
!=
non equal
<=
less than or equal
>=
greater than or equal
<
less than
>
greater than

The following example tests if $i is less than 3, and continues to loop until $i is equal or greater than 3:
; === while loop
$i=0
[ $i < 3
>echo "hello $i"
<hello $i
+$i
]
Nesting of while loops are also supported:
;; == Nested while loops, should repeat "hello ken" 3 times
;; == with 2 "bye now's inside each outer loop
>
$i=0
[ $i < 3
>echo "hello ken"
<ken
$j=0
[ $j < 2
>echo "bye now"
>
+$j
]
+$i
]
Foreach Loops

Code blocks also support foreach loops, where a loop will iterate of a known number of items. Each iteration, the variable will be set to the next item in the list. Items in a list must be separated by spaces. As of version 4.6.1, the list variable will be normalized (extra spaces removed) before executing the loop. Use string math functions to create a list of items separated by spaces.

In the following example, a list of network connected devices are named after planets. The variable $planet will be set to mercury, then ping it. Next time through the loop, $planet will be set to venus, then ping it, and so on. After the last item, neptune, the loop will complete and the script will continue after the bottom of the code block.
; === foreach loop
[ $planet=mercury venus earth mars jupiter saturn uranus neptune
>ping -c1 $planet
]
Of course, foreach loops can be nested with other foreach loops, or while loops.

Infinite loop protection applies both the "jump-to-label" method as well as to the "while-loop" and "foreach-loop" methods, each iteration of the loop decrements the infinite loop counter (default is 5000). It may be a good idea to set the infinite loop value to something low, when first writing code block loops, just in case:
*INFINITE_LOOP 20

Slowing Loops with sleep

For years, I have resisted putting a sleep function in expect-lite. Sleep is often abused by scripters who blindly put in a 60 second sleep (or longer). I have seen 5 minute (600 seconds) sleeps put into scripts because the scripter didn't want to poll for a change in device status. Long sleeps are just bad programming, and should be avoided.

Version 4.9.0 adds native support for sleep. There are very valid reasons why in the polling loop, the scripter may want to slow things down, and only check device status, say every 5 seconds. This can easily be done with a while loop:
; === while loop with sleep
$eth_status=DOWN
[ $eth_status == DOWN
>ip link show dev eth0
+$eth_status=(DOWN|UP)
:5
]
The script will check eth_status of eth0 every 5 seconds, and continue (exit the while loop) after $eth_status is no longer DOWN.

While the script is sleeping, if *INFO is enabled, expect-lite will print out a ticker of "dots" to indicate that the script is sleeping:

$ ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

Assigned Var:eth_status=UP

Sleeping: 5
....+
Sleep "dots" include dots, plus (every 5 seconds) and a number (every 10 seconds), to show the progress of the sleep.
Sleeping: ....+....10....+....20.... 
Mili-second sleep is also supported by using a decimal value for sleep, e.g. 0.005 equals 5 mili-seconds
#sleep 1/10th of a second
:.1
Of course, sleep value can also be a variable:
#sleep using a variable
$sleeper=5.5
:$sleeper
Please use sleep wisely.

Script Help with --help -h

Once the script running, it might be handy to add help to make it more user-friendly or refresh the mind when running the script at a later date. As of version 4.3.0, t is possible to use the build-in script help function which when --help or -h are typed on the command line, a help section and assigned variables will be printed.

The help section is defined in the script as a block of text which starts with a triple-semi-colon, and ends with a triple-semi-colon, text inside this block will not be executed by the script. For example:
;;;
Test: Test bash here doc

Assumptions: bash
Platforms: anywhere bash runs
;;;
Then when running the script, with the --help or -h cli argument, the following will be printed
$ ./test_bash_here_doc.txt -h
Help for: ./test_bash_here_doc.txt

Test: Test bash here doc

Assumptions: bash
Platforms: anywhere bash runs

Displaying assigned variables, which can be overridden with
a Constant on command line e.g var=value
tempfile=junk
The second portion of the help is a list of variables inside the script which can be overridden as constants (see Constants) on the command line. The assigned variables section of the help will always be printed regardless if a triple-semi-colon help block has been defined in the script. This is useful for older scripts which do not have a triple-semi-colon help block.

Constants are a very powerful feature of expect-lite which allow the behaviour of the script to change without having to edit the script. In the example above, if the script were run with the following arguments:
$ ./test_bash_here_doc.txt tempfile=/tmp/mydata.txt
When the script runs, rather than creating a file called 'junk', it will instead create a file in the /tmp directory called mydata.txt


Expect-lite & Bash

Although not limited to working with bash, bash is invoked upon logging into the remote host, and therefore will be discussed more here.

Since the bash shell is well documented, and supported, and therefore can be leveraged to assist in expect-lite's limitations such as looping and branching (see limitations below). A simple bash loop inside expect-lite can be created for example:
$set=1 2 3 4 5
>for i in $set #expanded by expect-lite
>{
>echo $i #expanded by bash
>}
In the above example, $set is an expect-lite variable, not a bash variable. An expect-lite variable is always declared before its use (e.g. $set= 1 2 3 4 5). If a variable cannot be dereference by expect-lite it is passed to the shell. The loop will execute after the final "}" line is sent to the remote-host. Because of this "execute after" effect, an expect-lite '<' line can not be used within the bash loop.

Another example is the bash while loop:
$max=5
>i=0
>while [ $i -lt $max ]
>do
>echo $i
>let i+=1
>done
Conditionals via bash are also supported, as in this example:
$max=4
>if [ $max -ne 5 ]; then
>echo "max is not equal to 5"
>else
>echo "we have a winner"
>fi
More complex bash assists can be constructed. For example, one may want to set a looping variable based on the processor type of machine at the time (some hosts may be faster than others). The answer is echoed, and then captured using a dynamic variable. Note that that 'proc' is prepended to the answer, as it enables the capture to be much more specific.
>PROC=`uname -i`
>if [ "$PROC" == "i386" ]; then
>echo proc20
>else
>echo proc100
>fi
+$loop_counter=\nproc([0-9]+)
Note that 'proc' is outside the parenthesis, and therefore will not be captured into the expect-lite dynamic variable $loop_counter.

Using Bash to create executable expect-lite scripts
It is possible to make expect-lite scripts executable. The old way was to use an embedded bash script, but version 4.0.1 makes this task more standard. Insert the following at the top of the expect-lite script:
#!/usr/bin/env expect-lite
The final step to making the script executable is to use a chmod command:
chmod 775 my_expect-lite_script.elt
Now the expect-lite script can be run my typing the following:
$ ./my_expect-lite_script.elt -r host-15 -u craig max_loop_count=100
The old bash scriptlet method can be found in expect-lite.proj/examples/test_masquerade.txt

Include Files

Include files are a quick way to develop script snippets which can be included into larger scripts or to include a common variable file. When an include file is executed, it is as if the file were just pasted into the script file, and therefore has access to the variable space of the main script, and can modify that variable space as well. In this example, a common variable file is "sourced":
# Source common variable file
~asic_vars.inc

Common functions, such as telnet'ing to the DUT, are a good use of include files. With version 4.3.0, it is possible to pass var=value parameters to the include file. The var=value operate just like constants overriding variables inside the include file (with a scope of just the include file). In the following example it is possible to override the variable 'user' and assign the value of 'root':
; === Connect to DUT 
~dut_connect.inc user=root
Include filenames can also be assigned in a variable, such that the file names can be declared at the top of the script but used later within the script. For example:
# Source Var file to be used
$asic_include=asic_vars.inc
...
~$asic_include
Include files can also be used for a simple regression, including each sub-script (see regression example) . If the *NOFAIL directive is used, and something inside an include file should fail, a failure message will be reported at the completion of the include file:
##Include Result: FAILED: dns_connect.inc    
Limitations on include file names

With the version of 4.7.0, a line beginning wih tilde character has a dual purpose, marking a fuzzy expect line, and also include files. This means that an include file name must NOT start with a greater than '<' or an equals '='. All other characters should be allowed in an include file name.

Embedded Expect

There are situations when expect-lite cannot provide a solution. Rather than force the user to abandon the simplicity of expect-lite, an embedded expect is supported. This functionality is provided to assist expect-lite rather than replace it. Lines beginning with '!' will be interpreted as native expect (see limitations below).

Embedded Expect requires the script writer to know  native expect. It runs with some variable protection, and provides access to expect-lite variables and constants, as well as the expect variable timeout. This permits the script writer to query the timeout, store it away, and then reset the timeout later.
# Preserve old timeout using embedded expect
!set user_namespace(TIMEOUT) $timeout
# set timeout to 15 seconds - max time to wait for login prompts
@15
>telnet $dut_ip
<login
>>root
<assword
>>my_secret
>
# Set the timeout back to old timeout
@$TIMEOUT
Expect-lite variable/values are stored in the tcl array user_namespace() with the variable name as the index name. Constants are stored similarly in the tcl array cli_namespace().

Expect code is collected in islands and executed after an island shore is reached. The island shore is represented by lines that start with any special character, except '#' and blank lines. However, it is recommended that the '>' be used, as this implies a "wait for prompt."

Branching and looping are supported in embedded expect e.g.:
!if { $arch == "ppc" } { 
! puts "\narch is $arch\n"
!}
>
And looping:
!for {set j 1} {$j<6} {incr j} {
! if {$j == 1} {set type "abc" }
! if {$j == 2} {set type "def" }
! if {$j == 3} {set type "hij" }
! if {$j == 4} {set type "lmn" }
! if {$j == 5} {set type "qrs" }
!
! puts "$j>$type"
!}
>
Provides access to expect send & expect commands:
!send "ls\n"
!expect -re "test" { puts "got test"} timeout {puts "got nothing"}
Embedded expect can fail the entire expect-lite script by calling the built-in _el_fail_test function:
!if { $arch == "ppc" } { 
! puts "\narch IS $arch\n"
! } else {
! puts "\narch is NOT ppc, but $arch\n"
! _el_fail_test
! }
>
TCL files can be sourced, and functions can be declared and called from within embedded expect.

Limitations of Embedded Expect:
  • Limited support of expect global variables. To declare a variable at the top level as global use "set ::<var> <value>" The double colon '::' makes var global (this is a TCL standard)
  • tcl/expect switch command not supported
  • expect statements must be on one line (as in the example above)

Please remember, this functionality is to provide assistance to expect-lite rather than replace it. (see What's Missing)

Expect-lite Directives '*'

Expect-lite directives are indicated by lines which start with the asterisk, '*'. The directives change the behaviour of expect-lite in a user defined manner. These directives include:
  • fail script - run when the script fails *~include_fail_script
  • user defined prompt - for those non-unix/linux remote hosts */regex/
  • stopping the script - *TERM & * FAIL
  • setting the default shell - **SHELL
  • multiple sessions - for hard to script environments *FORK
  • managing logging - *INFO, *NOINFO, *WARN, *NOWARN, *DEBUG, *NODEBUG, *NOCOLOR
  • debugging aid - *INTERACT (see debugging tips)
  • print all expect-lite variables - *SHOW VARS
  • control end of line character(s) - *EOLS LF, *EOLS CRLF
  • control dynamic variable capture method to require a prompt or not *DVPROMPT, *NODVPROMPT
  • allow script to run to completion regardless of failure status *NOFAIL
  • ignore breakpoints (used for regression) *NOINTERACT
Directives can also be placed on the command line at run time. This is useful for controlling logging, such as *NOINFO or *NOCOLOUR. Additionally, *NOFAIL can be useful when debugging a script, since the script will not stop prematurely.

Fail Script    *~include_fail_script

The purpose of the fail script is to clean up after the failed script, reseting times, deleting temporary files and such. It is a special include script which is declared near the top of the script:
*~clean_up.inc
Should the script fail, the fail script will be "sourced". 

The scope of the fail script is always local to the running script. This allows normal include scripts to declare a separate fail script from the main script. Thus enabling a different clean up mechanism for the include script.

The fail script mechanism should no longer be needed  for script development. The technique was useful before debugging tools like instant-interact and the powerful IDE built into version 4.0.1.

User Defined Prompt   */prompt/

With each '>' command an implied "wait for prompt" occurs (see implementation details). The predefined prompts are based on standard shell prompts (>%$#). However, it is quite possible that expect-lite will not be interacting with a shell, but another application (such as gdb) or device which does not issue a shell-like prompt.

As of version 3.1.5, the user may define a custom prompt. User defined prompts are defined from the newline (beginning of line) to the end of the prompt. For example:
*/my_prompt /
The succeeding  '>' lines will interpret a prompt as the standard shell prompts and 'my_prompt '. The user defined prompt definition between the slashes is interpreted as regex, and therefore regex rules such as escaping applies. For example, to set a user defined prompt for gdb the following would be used:
*/\(gdb\) /
Only one (1) user defined prompt can  be active at a time, however multiple prompts can be represented using the regex OR '|', for example, creating a gdb prompt and my_prompt:
*/\(gdb\) |my_prompt /
Another application of the user defined prompt is to make telnet logins easier:
*/login: |.+ssword: /
>telnet remote-host-018
<Connected to
>$username
>$password
>
Clearing a user defined prompt. There may be times where a previously user defined prompt is causing problems by output which falsely triggers the user defined prompt. It is possible to clear the user defined prompt by:
*//
Debug the user defined prompt by using the -vv or --verbose cli parameter. In the example below, the user defined prompt has been incorrectly */\(gbb\) / while running gdb (a linux debugger). The debug output shows the user defined prompt and the string expect-lite is searching for the prompt.
(gdb) Warning:Prompt Timed Out!
DEBUG: User Defined Prompt:<<\(gbb\) >>
Not Found in<<
(gdb)
>>

The scope of the user defined prompt is global, that is, it extends to the main script as well as all include files referenced.

Setting the default shell with **SHELL=<shell>

expect-lite has been tested with bash, however it should operate with other shells. Based on the user's preference, a shell can be selected with the **SHELL directive. Because the shell is invoked immediately after login to the remote host, this is a configuration directive with is read before the script executes. Therefore, it can be placed anywhere in the script, and is not limited to the first line.

Stopping the script early with *TERM, *PASS & *FAIL

There are times when it is desirable to terminate the execution of a script early (earlier than the end of the script). For example, while debugging a script, it is convenient to stop execution mid way in the script while focusing a troublesome section. Or to perform a test, such as this is Monday, and terminate the script.

*PASS will stop execution and return 0, or Pass. This is useful for debugging. *TERM <N> (as of version 4.8.0) will terminate the script early, and return N (0..255). User defined return can be useful for signalling to the calling program that the script returned abnormally (e.g. lab setup was not correct).

*FAIL will stop execution and return 1, or Fail. If a fail script has been declared earlier, it will be executed before terminating execution. If *NOFAIL has been used prior to *FAIL, then the script will run to completion, but will declare fail at that time, and return 1.

No stopping the script with *NOFAIL

There are times, especially when debugging a script, where it is desirable to not stop the script due to a failure, but instead allow the script to run until completion. Setting the directive *NOFAIL will prevent the script from terminating prematurely. Once invoked, there is no disabling *NOFAIL.

Upon completion, if there are failures during the script, expect-lite will return a 1, and indicate that there was a failure.

More no stopping with *NOINTERACT

When running regression scripts, it is not desirable to have each include script stop at breakpoints (*INTERACT). Rather than force the re-editing of each include file, it is possible to ignore the breakpoints with *NOINTERACT.

This directive is sticky, and can not be turned off once it is invoked.

Debugging by examining expect-lite variables with *SHOW VARS

It can be useful when debugging a script to see what the value of variables are at some point in the script. Additionally, overriding constants will also be printed. This can be used with *INTERACT, or pausing the script, however using the debugger command <esc>v is less typing.

Multiple Sessions *FORK

Until version release 3.5.0, expect-lite has been intentionally limited to a single session keeping it simple. However, there are certain environments where it might be advantageous for a single script to control/monitor both a client (e.g wget) and a server (httpd log). Without multiple session support this type of environment would be difficult to automate with expect-lite.

What is a new session? A new session starts with a new shell on the remote host. All commands '>' and received text '<' are constrained to that session. It is possible to use multiple sessions on the localhost using r=none, however r=none support is limited due to timing issues (the timing issues have been removed in 4.7). If multiple sessions on the localhost (the same host where expect-lite is running), it is better to ssh to the localhost by specifying r=localhost. This loop back method ensures that the timing between commands and received text stay in sync.

With the version of 3.5.0, expect-lite supports nearly limitless multiple sessions. However, it is a good guideline to use as few sessions as needed. For backward compatibility, the first session is the "default" session. Additional sessions are assigned a name at invocation with the *FORK <session_name> directive:
*FORK Server
INFO: FORK session is: Server
expect-lite will print an "INFO" line stating the current session name
Session names may not contain spaces, and must be unique for each session. To switch back to a previously started session, re-use the session name. The session name "default" (without quotes) is reserved for the first session.
*FORK default
INFO: FORK session is: default
Print the current session name by using the *FORK with no session name:
*FORK
INFO: FORK session is: Server
*FORK and variables. It is possible to assign a session name to a variable, and then create a new session with that name. For example:
$my_session=Client
*FORK $my_session
INFO: FORK session is: Client
All sessions will be automatically closed when the script terminates.

Debugging in a multi-session environment: When in INTERACT, either via the *INTERACT command in the script or via instant-interact (by pressing ^\), the *FORK command is still available, permitting the switching of sessions while in INTERACT mode. For example:
expect-lite directive: *INTERACT 

Press '+++' to end interact session & return to script

% *FORK CONSOLE

INFO: FORK session is: CONSOLE, Active sessions are: default CONSOLE
#

With the addition of multiple sessions, decoding the output will become more difficult. Remember, although multiple sessions are supported, expect-lite is still single threaded, meaning commands will always be executed the order as they appear in the script.

Managing Logging *LOG, *LOGAPPEND, *NOLOG, *INFO, *NOINFO, *EXP_INFO, *NOEXP_INFO, *WARN, *NOWARN, *DEBUG, *NODEBUG, *NOCOLOR

Expect-lite provides additional information (logging) which makes it easier to debug failures. As of version 4.4.0 expect-lite supports native saving output to a file (logging). Using *LOG, *LOGAPPEND, and *NOLOG, logging can be controlled within a script. On the CLI,  the *LOG commands will override those inside the script.

The following logging commands are supported:
  • *LOG: with no file name, will automatically create a log file with the script name + ".log" in the same directory as the script. If a path/file name is supplied, expect-lite will write standard out and additional info (INFO, WARN, DEBUG) to the path/file name file. Because parameters can be entered in any order on the CLI, the path/file_name must end in ".log" to prevent ambiguity.
  • *NOLOG: closes any open logging files, and disables any additional output from be saved to a file. When used on the CLI, all logging to a file will be disabled.
  • *LOGAPPEND: Will cause output to be appended to an existing file, or create a new file if existing file doesn't exist. Output will be appended to path/file_name, when using *LOGAPPEND <path/file_name>.
The output is coloured based on three levels of information desired: info, warnings, and debug. By default, info and warnings are turned on and exp_info is turned off.  However, using the log information directives: *INFO, *NOINFO, *WARN, *NOWARN, *DEBUG, *NODEBUG, these messages can be managed. Additionally, *NOCOLOR, will turn off color output.

Example of the different information levels are:
  • INFO: Entering FORK sessions, Constant substitution, Conditional Statement Results, Jumping to labels, Including files, Dynamic Variable Assignments, User Defined Prompt assignments, Sleep progress dots and ##Overal Result.
  • EXP_INFO: prints "expected" text (lines with < or <<). Also enabled with -V flag on the command line.
  • WARN: Instant-Interact feature disabled, Wait-for-prompt timeouts, Using localhost (r=none), Unable to parse Conditional, Dynamic Variable Capture timeouts, Unable to parse math variable statement, Unable to parse FORK session name, Unable to parse Conditional Statement
  • DEBUG: Additional debugging information for: User Defined Prompt, FORK session instantiation/switching, '<' searching, Dynamic Variable capture
In addition to the Logging Directives, invoking expect-lite with a -v or -vv will force INFO & WARN on or WARN & DEBUG on, respectively. It should be possible to direct the amount of logging desired by using a combination of the command line arguments (-v or -vv) and the Logging Directives.

In addition to the three logging levels above, there is another more serious level of ERROR, which can not be suppressed, and will terminate expect-lite with a non-zero return code. Examples of ERRORs are: unable to connect or lost connection with remote host, include file not found, or infinite loop detection.

It may be tempting to turn off logging once a script is debugged. However, if the script is being run in an automated environment (like crontab), it is recommended that INFO and WARN be turned on, as the additional information will make debugging failures much easier.

Controlling End of Line Sequence with *EOLS

There are some remote devices which require carriage return + line feed at the end of each line sent. In past versions of expect-lite, only line feed was appended to each '>' or '>>' line. This limitation made it difficult to automate tasks with this class of remote devices.

With version 3.7.0, the end of line sequence can be controlled with the following expect-lite directives: *EOLS LF & *EOLS CRLF. The default is *EOLS LF.

These directives can be placed anywhere in the script and the setting remains in effect until another *EOLS directive is encountered. For example, enabling a script to control a linux machine (using *EOLS LF), and later in the script controlling a remote power-switch device (using *EOLS CRLF).

Controlling Dynamic Variable capture method with *DVPROMPT/*NODVPROMPT

The default Dynamic Variable Capture method requires a trailing prompt to signal when to look for the text of interest. This is based on the assumption that a command would be issued, and somewhere in the output is the text of interest. For example:
$ date
Sat Jul 19 18:19:58 EDT 2014
$
A Dynamic Variable capture script might be looking for the month.
>date
+$month=\n\w+ (\w+)
With the default capture method, *DVPROMPT, expect-lite will wait for the trailing prompt (after the date output) before searching the output for $month. If the text of interest (e.g. month) is not found, then a warning will be issued, and the script will move on quickly.

There are times when there is no prompt (e.g. it is just the running output of /var/log/messages), and the default dynamic capture method will not find the desired text.

*NODVPROMPT turns off the requirement of the trailing prompt for these instances. The Dynamic Variable capture method will search the output until the timeout value (set with @, e.g. @5) expires. Caution: this can slow down the script considerably, if the expect timeout is set to a large value, say 600 (10 minutes), and the text of interest doesn't appear. The script will just sit and wait for 600 seconds, before issuing a warming and finally moving on.

Like all directives, *DVPROMPT/*NODVPROMPT can be used at anytime in the script,  on the command line when invoking the script, or even in the Debugger.

Examples of Expect-lite

Below are some examples to better illustrate what can be accomplished with expect-lite:

Setting an IP address
Setting the IP address on a secondary interface of the remote host (be sure to escape the dot's in the IP address)
$local_eth=eth1
$ip_addr=192\.168\.10\.2
# change timeout value to 10 sec
@10
>ifconfig $local_eth $ip_addr
#check to ensure that we set the right IP address
>ifconfig
<$ip_addr
Telnet to another host
Starting a telnet to another host
@2
>telnet remote-host-018
<Connected to
<login
>>root
<assword
>>secret_password
# issue a command once logged in
>pwd
>^]
>quit

ssh to another host
Starting a ssh session to another host
>ssh root@host-021
<assword:
>>secret_password
# issue a command once logged in
>ls
>exit

Use Screen to keep session alive
Use of 'screen' command to keep a command alive after test completes
; ==== Use Screen command for to keep application running ====
>screen
> $pmm
# Check that HW is alive
>ping
<Successfully pinged the PM H/W
; ==== Keep pmm application active, and detach from this screen
>>^A
>>^D
<detached
>
Assigning a dynamic variable
Assigning a dynamic variable $host using regex to capture the hostname from 'uname -a' command
>uname -a
+$host=Linux ([a-z\-0-9]+)
Assigned Var:host=remote-host-008
>
Assigning multiple dynamic variables using regex to capture environment variables $HOME and $SHELL, while expecting $TERM=xterm
>env | sort
+$home=\nHOME=([a-z/]+)
+$shell=\nSHELL=([a-z/]+)
<TERM=xterm
Assigned Var:home=/home/joe
Assigned Var:shell=/bin/bash
>
Assigning a dynamic variable to a list of items (or multiple lines). The value of the dynamic variable will be a space delimited list (replacing end of lines with spaces):
#prompt is $ and space after $
$prompt=\$
>env | sort
+$env_list=((.|\n|\r)*)$prompt

Allowing multiple responses with RegEx
Using regex in expect-lite to expect users OR wheel
>id
# allow either groups users or wheel
<(users|wheel)
Use of bash-here-doc to create temp file
Create a temporary file with unique name including script name and date. The predefined variable $arg0 is contains the expect-lite script name.
# date stamp of script run time
>echo `date +_%Y_%m_%d_%H-%M-%S`
+$DATE=\n(_[0-9_-]+)

$temp_file=$arg0$DATE
; === Create a temp file using bash "here doc" method
>cat > $temp_file <<'+++'
>line 1
>line 2
>+++
>
Force arguments with help
Creating script help. First, require a parameter be passed via the CLI, such as sw_build:
./upgrade_script.elt sw_build=0015
Inside the script itself, default $sw_build to 0, the CLI constant will override.
$sw_build=0000
; === Check passed parameters
>
*NOINFO
?if $sw_build != 0000 ? %CONTINUE
;; ##############################
;; $arg0 Requires parameters: sw_build, IP
;; e.g. $arg0 sw_build=0015 IP=10.3.5.4
;; ##############################
# quit the script without continuing
*FAIL
%CONTINUE
*INFO

Now when just the script is executed, help will be displayed, and the script will terminate.
./upgrade_script.elt

=== Check passed parameters

expect-lite directive: *NOINFO
##############################
upgrade_script.elt Requires parameters: sw_build, IP
e.g. upgrade_script.elt sw_build=0015 IP=10.3.5.4
##############################

expect-lite directive: *FAIL

User Defined Help
As of version 4.3.0, User defined help can make scripts more user-friendly. Text between triple-semi-colons ';;;' will be displayed when the -h or --help option is used on the command line
;;;
Test: Test bash here doc

Assumptions: bash
Platforms: anywhere bash runs
;;;
Then running the script, the help text as well as variables  in the script which can be overridden on the command line (as constants).
$ ./test_bash_here_doc.txt -h
Help for: ./test_bash_here_doc.txt

Test: Test bash here doc

Assumptions: bash
Platforms: anywhere bash runs

Displaying assigned variables, which can be overridden with
a Constant on command line e.g var=value
tempfile=junk

Sample Regression Script
It is possible to use expect-lite to run simple regressions by including multiple include files. It is also possible to pass var=value parameters to the include files changing the nature of the test. In the following example, pseudo-arrays and a while loop is used to create a quick regression.
# ignore breakpoints in include files
*NOINTERACT
# do not stop on failures
*NOFAIL

######### List of tests to run in regression
$blank=
$tc0=ipv6_telnet.elt
$tc1=ipv6_ndp.elt
$tc2=ipv6_self_syslog.elt mode=ipv4
$tc3=ipv6_self_syslog.elt mode=ipv6
$tc4=

$start=0
$count=$start

[ $tc$count != $blank
; ============== starting $tc$count
~$tc$count
; ============== end $tc$count

# increment variable
+$count
]

Run the regression script and log it using the unix/linux 'tee' command. By defining 'start' as a constant on the command line, it is possible to start the regression with the second test.
./regression.elt start=1 *LOG

Test Failure?!?

When will expect-lite fail a test? It will only fail a test when an expected result (after issuing a command) does not appear in the specified timeout period. For example in the following command file:
$ip_addr=192.168.10.99
>/sbin/ifconfig eth0 $ip_addr
>/sbin/ifconfig eth0
< $ip_addr
The first line will be sent (blindly), since there is no expected return. On line 3, the ifconfig command is sent again, and the script is looking for a desired result of  192.168.10.99 (using the var $ip_addr). If for some reason the ip address is different than ip address was returned, the script would fail.

Not Expect
A test can also fail should text appear that is unexpected (such as an error). This does not clear the expect input buffer, and should be used before a valid expect. How long should the script wait for the un-expected? In order to reduce delays in script running time, the Not Expect feature only waits for 100ms. This is usually enough time to detect quick error responses such as "file not found". 

For example: Fail device doesn't exist
>ls -l /dev/linux
-<No such file
In another example: We don't like Mondays
; === fail if today is 'Monday'
>date +%A
-<Monday
Since the expect input buffer is not consumed, valid expects can still be performed. in the following example, ttyS2 will still be found.
>ls -1 /dev/ttyS*
-<ttyX
<ttyS2
It is recommended that Not Expect lines be used before valid expect lines. There is an exception to this rule, when looking at output which may be slow (longer than 100ms). For example there may be a linux machine with several interfaces (eth0 thru eth4). You may want to ensure that eth4 is not down.
>ip link show
<eth4
-<state DOWN
In the example above, the 100ms counter will start after finding 'eth4'

Fuzzy Expect
Fuzzy expect is expecting an approximate number (either decimal or hex). There are situations where an approximate value, or a range of numbers is acceptable. An example, one might be looking at cpu load (it is OK if it is between 0 and 2, but the test should fail if it over 2).

Fuzzy expect operates in two parts. The first part is to set a range or tolerance (of fuzziness). This defines a range, for example entering 7, will match + or - 7. Set the range by:
; set the fuzzy expect range to 7
~=7
This value will be in effect until it is changed.

The second part is to use fuzzy expect. In the following example, it is important to the script to run in the first 2 weeks of the month. Using the date command to print out the date/day of the month.
; Check the date/day of the month
>date "+the day is: %d"
~<the day is: (7)
The value in parens will be checked against the range earlier defined (plus or minus). In the above example, if the date command returns the string "the day is : 13", it will be pass, since 13 < 7+7

Of course this could have been done in a more programmatic way, of capturing the value returned by date (using Dynamic Variables), then using a conditional (if statement) to do the comparison. But fuzzy expect is much simpler to use.

Additional important details are: it consumes the expect buffer, hexidecimal numbers must start with 0x (e.g. 0xbeef),  parens in the string which are not matching the fuzzy value must be escaped with a backslash (e.g. \(15\) ), regex evaluation is active (like '<'), and the default range is 10.

How can it help?

Expect-lite can be used to quickly create automated tests. It can collapse complicated tests into a single command line. It can also be used in nightly regression testing, performing simple functional tests providing confidence that core functionality has not been broken by the previous day's submissions.

Limitations


Expect-lite is limited to what a person could do in one (1) terminal window (or xterm). It cannot start a program in one window and run a different program in a separate window. However it does support multiple sessions via *FORK which should meet the needs of most.  

Standard programming constructs such as looping and branching are supported as of version 3.0.0. Real Expect can do these things and more. That said, looping is limited to a repeat loop and while loop and branching can be accomplished with Labels.

Expect-lite has been purposely limited to keep scripts simple, easy to use and maintain. Although more complex scripts can be created, basic expect-lite scripts can be created by simply cutting and pasting text from a terminal window into a script and adding '>' '<' characters.

Implementation Details

Variables

Variable names must be restricted to the following set of characters [A-Za-z0-9_]. Variable values may include spaces, and quoting is not required nor permitted. For example:
$bell=For whom the bell tolls
>echo $bell
For whom the bell tolls

Implied "wait for prompt"

Using the '>' character implies waiting for the prompt before sending the command. The definition of a shell prompt a: $, #, % or >. It is often useful to follow a '<' with a '>' for force the script to wait for the prompt:
> $some_long_command
<critical value
# wait for prompt
>
Prompt detection can be problematic, and by no means is expect-lite's method perfect. Expect-lite looks for a prompt character ($, #, % or >) followed by a space at the end of line. This should work for most standard prompts, however coloured or fancy prompts may not be detected. As of version 3.1.5, user defined prompt is supported.

It may be useful to create files on the fly which will be used in the test. Since expect-lite does not read/write files directly, this function can be done with the linux command 'cat' and the bash here doc method. Creating a regex file for example:
; ==== Create Test File on the fly
> cat > $regex_test_file << '+++'
>T00001/a(?$XL.*)/tag=0x08000001
>T00002/b(?$XR.*)/tag=0x08000002
>T00003/c(?$XO[0-7]*)/tag=0x08000003
>T00004/d(?$XH[0-9A-F]*)/tag=0x08000004
>T00005/e(?$XD[0-9]*)/tag=0x08000005
>+++
>
In the above example the script initiates a cat to a file (referenced by $regex_test_file ). Normally the '>' would be used to send lines to the remote host. However, there is an inherent "wait for prompt", which will politely wait for the next line. The last '>' is there to wait for the prompt to return after the cat command.

Predefined variables

Expect-lite has minimized the use of predefined variables to allow the user the widest latitude in selecting variable names. However a few predefined variables are useful and listed below:
Predefined variable
Usage
$arg0 expect-lite script name. Set to the c= or cmd_file= value. Useful for creating temporary files unique to the test script.
$timeout_multiplier Typically used as a constant (passed in from the command line) which the integer value is multiplied by each of the timeouts in the script. i.e. @10 x $timeout_multiplier = real timeout. The value default is 1.

Timeouts

Setting the expect-lite timeout to 0 isn't actually zero as this will cause the keyboard input buffer on the remote machine to overflow (and lose characters). Expect-lite adds a 50ms delay between lines when the @0 is used to prevent the overflow.

Expect Input Buffer

Expect by default places strings that are sent back (from the remote host) into an expect buffer ($expect_out(buffer)). Expect-lite leverages this built-in function, and uses it to perform multiple searches through the buffer when using the '<' , '+<' or '-<' actions. The actions '>' and '>>' will clear expect buffer to prevent spurious matches.

The default size of the expect_out(buffer) is 10000 bytes. This has been selected as a compromise between performance (larger buffer slows down searches), and large enough for most users. If searches (using '<' , '+<' or '-<') or dynamic variable captures are being truncated, it may be required to increase the size of the expect_out(buffer) size. Caution: This should only be a last resort (as it will impact performance). Place the following near the top of the script.
; === set expect buffer big
!match_max -d 20000

Timing is everything: delay_wait_for_host

When communicating with a remote host, enough time must be provided for the remote host to respond. There is an internal global value of $delay_wait_for_host (in mili-seconds) which can be tuned to your environment using the environment variable EL_DELAY_WAIT_FOR_HOST (see sample bashrc). This value is also used by the Expect Not feature to determine how long Expect-Not should wait for the unexpected.

Unsynchronized messages disclaimer

Effort has been put into making the output as synchronous as possible. However because what is seen on stdout or screen is data returned/echoed from the remote host and printable comments are directly printed to stdout, it is possible to have a printable comment appear in the stdout before the action it references is returned from the remote host. This lack of synchronization can sometimes be minimized by adding an additional '>' after the printable comment as shown in the following:
; === starting long command
>
>start_long_command

Instant-Interact: More than just a pretty prompt

When the user presses ^\ (control+backslash) during the running of a script, expect-lite will drop into interactive mode aka the integrated debugger. In version 4.0.1, the debugger has been greatly enhanced and performs three primary functions: 1) connecting the user to the remote host or device under test, 2) monitoring special commands prefaced with the escape key for stepping, and other functions, and 3) the debugger will allow expect-lite script lines to be executed by either typing directly or pasting them into the debugger. The TCL package TclX is no longer required.


Control will be returned to the script when '+++' is typed. In addition to returning to the script, the current command in the script will be "Passed", preventing it from failing the script. This is useful when debugging a script, the user notices that the response is not as expected, and presses ^\ to move to interact mode. Returning from interact mode, the line which would have failed the script (because of the response not being as expected) will be "Passed" and the script will continue. This Passing action is line oriented, and other '<' lines in the script can still fail the script.

 In the IDE (debugger), expect-lite script commands can be typed, even assigning variables or displaying them inside the paused script, for example:
$MYVAR=today

*SHOW VARS
Var:0 Value:0
Var:MYVAR Value:today
Var:TEST Value:/proc/cpuinfo

>>pwd
pwd
/home/user
Additionally, expect-lite lines (code fragments) can be copied from your favourite editor and pasted directly into the debugger. All variables will be automatically dereferenced (assuming they were set in the first place). This is very useful for testing Dynamic Variable capture lines, which can be tricky to define.

When lines are pasted into the debugger, or the Step or sKip function are used, the debugger clumps lines which begin with '>' and any following lines with start with '<' or '+$' This enables expected results and dynamic variables to be interpretted correctly. For example:
# clump 1
>ls /etc/
<group
<passwd

#clump 2
>date "+TIME: %H:%M:%S"
+$time=\nTIME: ([0-9:]+)
If the above lines are copied and pasted into the debugger, in fact they will be executed as 2 clumps. Usually this is of no concern, however when stepping/skipping through an expect-lite script, one will notice that clumps are executed rather than indivdual lines.

*FORK: what happens behind the scenes

A new *FORK session actually creates an additional login(s) to the remote host from the localhost using the same connect method as the first (or default) session. It then sets a sane prompt, and waits for the first script command in that session. This provides multiple sessions on the remote host, which then could be used to drive separate programs (see test_fork_web_client_server.txt for example). Graphically it would appear as:
Localhost Remote Host
+----New_Session1--->Client App
+----New_Session2--->Server App

What's missing

In order to maintain an easy-to-learn, simple-to-use expect like language, looping has been intentionally kept simple and intuitive. Most expect-lite scripts will be to be top down, single pass scripts, making the scripts easy to create and read. These limitations preserve the KISS principle.

If more complexity is required, consider using embedded expect inside expect-lite, or writing a native expect script.

Why Expect-lite

Expect-lite was written so you don't have to learn expect. It provides a quick way to write simple expect scripts using just the > and < characters.



15 August 2015
http://expect-lite.sourceforge.net/

Subscribe to expect-list-users Discussion List

this document for version 4.9.0 and above


expect-lite.proj/Docs/expect-lite_press.html0000644000076400007640000001643612562233520021725 0ustar cvmillercvmiller expect-lite Buzz

greater than

expect-lite


Automation for the rest of us


What is being said about expect-lite?

From 2008:

Linux.com Review

Expect is a venerable tool for scripting interactive command-line tools. One normally sees expect coupled with the TCL programming language -- for example, in the DejaGNU test environment. Expect-lite is a wrapper for expect designed to allow you to capture an interactive session more directly mapped into a script. The expect-lite language also includes simple conditionals and other programming language elements, and can be readily mixed with bash programming. [more]

From 2010:

Lee Schlesinger's Blog

Developer Craig Miller created expect-lite after leaving a job where he worked with a proprietary automation language. "I wanted to use a more standardized language like Expect, but it uses just too many curly braces, and it is easy to create cryptic code, which is hard to debug. I wanted to create a simple language that focused on getting the job done, rather than making users spend hours learning and debugging. Expect seemed like a good place to start. [more]

Craig Dunn's Blog

I’ve recently been playing around with expect-lite, a wrapper for expect that allows you to automatically login to hosts with telnet or ssh to run commands on remote hosts without getting too much under the bonnet of expect syntax. [more]

Planet Ubuntu.es

When we want to write scripts that automatically perform a task such as connecting to a server and write the password without requiring us to be ahead, we often resort to use " expect ".  But using a priori expect is not as simple and requires some knowledge, to facilitate our work, we can now also expect-lite.

expect-lite is a simple automation tool.  Written in expect, this deiseada to map directly interactive terminal session in a script automation.  Basically automation scripts can be created by cutting and pasting text from one terminal and adding the characters ">" to what we send and "<" to what we expect. So expect no knowledge is required. [more, translated from Spanish]

From 2012:

antiCisco blogs

Unfortunately, most network equipment does not have any API for remote management, and if so, often writing for a client to send multiple commands did not justify the effort.

Fortunately, there has long been a tool to automate such tasks called expect. And there is a more convenient wrapper to him under the name expect-lite, which we are reviewing today.  For example, we write a script that will start the switch ports you want us to VLAN. [more, translated from Russian]

Andy Han's Blog (based in Beijing)

I need to update more than 2000 Redhat servers' resolv.conf file
expect is a good tool to achieve this, but expect-lite is cooler :) [more]

From 2013:

under-linux.org

The developers responsible for expect-lite, a wrapper for the Unix Expect tool, just released version 4.6.0 of their software. Among the new features include the inclusion of the foreach loop, and adding functions of type string-math. The location of the configuration of SSH login was also moved from the tool settings for the own configuration file in the SSH client... [Original in Calician]

Where to get it?

The most recent version is always available on SourceForge:

Download expect-lite



3 May  2014
http://expect-lite.sourceforge.net/

this document for version 4.7.0 and above

expect-lite.proj/Docs/expect-lite_install.html0000644000076400007640000002573312562233520022237 0ustar cvmillercvmiller expect-lite Installation and Quick Start Guide

greater than

expect-lite


Automation for the rest of us

Installation and Quick Start Guide


Download

expect-lite can be downloaded from the expect-lite Project Page: http://sourceforge.net/projects/expect-lite
The tar.gz/rpm/deb package includes the latest expect-lite, as well as over 25 examples.

Or, if you are running a modern version of Ubuntu: apt-get install expect-lite

Or, if you are running a modern version of gentoo: emerge -auv expect-lite

Or, download the RPM or DEB file (from sourceforge) and install using 'sudo rpm -Uv expect-lite*.rpm' or 'sudo dpkg -i expect-lite*deb' Then use the '/usr/share/doc/expect-lite/install.sh -c' to configure ssh and .bashrc if desired

Quick Install

To install using the tar.gz file: Prior to untaring the package, be sure to type 'umask 0' to preserve permissions of the package. Untar the expect-lite package, and use the included install.sh script (as of version 4.0.2). If on Linux/Unix/MacOS X, sudo permissions will be required to install:

Change directory to expect-lite.proj
cd expect-lite.proj
Run installer
sudo ./install.sh
Since cygwin does not require sudo previlages, just type:
./install.sh
Test by typing at the prompt:
expect-lite
If you see the help, then it is ready to go, installation is complete!

The install.sh has other options such as unprivileged install, and user configure only, which may be useful in your environment, refer to ./install.sh -h for more info.

Quick Start

Expect-lite has many features which make it useful, and the documenation highlights those. But to start using expect-lite quickly, you require two items:
  1. a script
  2. a host 
Here is a quick script which you can paste into a file to test expect-lite, call it test.elt :
; ==== Ping localhost and check result ====
@5
>ping localhost
<<127.0.0.1
<<127.0.0.1
<<127.0.0.1
>>^C
>
The second item you require is a host to run your script against. Expect-lite is designed to log into a remote host and run your script, as if a person was typing the commands. However that may require setting up ssh keys and so forth, and this is the Quick Start section. Type the following to run the above script on your localhost:
expect-lite -c test.elt 
There should be output that looks similar to the following:
cvmiller@maile:~/Freescale$ 
cvmiller@maile:~/Freescale$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.023 ms
sending ^C

^C
--- localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1007ms
rtt min/avg/max/mdev = 0.020/0.021/0.023/0.004 ms

##Overall Result: PASS
Congratulations you have just run your first expect-lite script! expect-lite is designed to run in a multi-user environment, utilizing shell variables to set one's preferences.

Customizing expect-lite

There are aspects of expect-lite which you may want to tune to your environment. The Installer will set up your .bashrc file to source the expect-lite configuration from .expect-literc. Customization is controlled through shell environment variables. A sample bashrc file is supplied in the expect-lite package. The contents of which are as follows:
# bashrc

# append this sample bashrc to your .bashrc to set customize expect-lite

# remote host to connect, default=none
# expect-lite was designed to automate server farm environments
# However, it can also be run from the local machine or PC by setting
# this value to 'none'. The CLI option -r <rhost> will overide this value
#export EL_REMOTE_HOST=localhost

# name of expect-lite script
# Good for testing one script over and over
#export EL_CMD_FILE=

# change to this dir upon login
#export EL_USER_DIR=

# Login method to remote host
# expect-lite includes a utilty (setup_local_ssh.sh) to automatically setup ssh
# keys for the user to use with the localhost. This is the fastest method
# of script execution, much faster than 'none'.
# Choose one login method: telnet|ssh|ssh_key|none
#export EL_CONNECT_METHOD=ssh_key
export EL_CONNECT_METHOD=none

# username for telnet|ssh|ssh_key access methods
# User is also used by ssh_key method as well. If user is blank then the default
# user will be used (the user running the script). However if $user is defined
# then ssh_key will use the following command: ssh $user@$host
#export EL_CONNECT_USER=

# password for telnet|ssh access methods
#export EL_CONNECT_PASS=

# Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture
# 100 ms is a good value for a local LAN, 200 ms if running across high speed internet
#export EL_DELAY_WAIT_FOR_HOST=

# User defined constants
#EL_*



EL_CONNECT_METHOD

expect-lite was designed for a server farm environment, and as such can automatically connect and log into a remote host. expect-lite supports three methods to connect to remote hosts.

Expect-lite supports three connection methods:
  1. telnet
  2. ssh
  3. ssh_key
The ssh_key method is the most secure, as no passwords are utilized. However this requires setting up ssh keys prior to using this method.
# Login method to remote host
# expect-lite includes a utilty (setup_local_ssh.sh) to automatically setup ssh
# keys for the user to use with the localhost. This is the fastest method
# of script execution, much faster than 'none'.
# Choose one login method: telnet|ssh|ssh_key|none
export EL_CONNECT_METHOD=ssh_key

There is a forth method, as shown in the Quick Start, where no remote login is performed. This method was designed primarily for the Quick Start section, however, it can be used for most scripts (including in the Cygwin environment). To invoke this method the value of "none" is given for the remote host on the command line.
expect-lite -r none -c test.elt
Even when no remote host is required, it is best to log into the localhost, since the underlying Expect has problems with synchronization (between send and expect strings) when a remote host is 'none'. The installer will detect if the install machine is running sshd, if so it will configure .expect-literc to use 'ssh_keys" and run the provided shell script 'setup_local_ssh.sh' (in the Tools directory) which will setup the localhost with ssh keys. This can also be one manually at a later time, it is only necessary to run it once:
./Tools/setup_local_ssh.sh

EL_CONNECT_USER & EL_CONNECT_PASS

The connection methods telnet & ssh require user name and password. A different user can be used for the ssh_key method as well, by setting EL_CONNECT_USER. The ssh_key is most secure since the user name and passwords are not used. However this may not be practical for your environment.
# username for telnet|ssh|ssh_key access methods
# User is also used by ssh_key method as well. If user is blank then the default
# user will be used (the user running the script). However if $user is defined
# then ssh_key will use the following command: ssh $user@$host
#export EL_CONNECT_USER=

# password for telnet|ssh access methods
#export EL_CONNECT_PASS=

The default username and passwords are blank, and are not used for the 'none' connection method.

EL_DELAY_WAIT_FOR_HOST

Because of the nature of accessing a remote host, expect-lite may have to wait for a response if the access is slow (eg. over a VPN via the internet).
## Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture
# 100 ms is a good value for a local LAN, 200 ms if running across high speed internet
#export EL_DELAY_WAIT_FOR_HOST=

The value of 100 ms is a good value for a local LAN, while 200 ms may be desired if running across high speed internet. As this value is increased the script will run slower. It is recommended that a minimum value be used to prevent scripts from taking too long to run.

EL_*

The last section of the sample bashrc file is reserved for the user. expect-lite will read in any shell environment variable which begins with EL_

The shell variables are treated as constants in the expect-lite script, overriding any internal variables.
# User defined constants
#export EL_*
export EL_root_pass=mysecret



19 November 2013
http://expect-lite.sourceforge.net/

this document for version 4.6.2 or later
expect-lite.proj/Docs/expect-lite_library.html0000644000076400007640000002056612562233520022234 0ustar cvmillercvmiller expect-lite as a Library

greater than

expect-lite


Automation for the rest of us now in Library form


Using expect-lite as a TCL Library

expect-lite can now can run in two modes: standalone, and library-mode. In library-mode expect-lite be used within a TCL (Tool Command Language) program.

What this means is that expect-lite can be called programmatically from TCL, allowing the integration of the ease of expect-lite scripting with a more complex TCL-based regression system. An example TCL program, test_el_lib.tcl, using library-mode is included in the tarball.

In keeping with the principle of 'keeping it simple', the goal is allow expect-lite scripts to be used unchanged, or with minimal changes, in a native TCL environment. Important differences from standalone mode are described below.

The expect-lite library seeks to leverage the ease of expect-lite scripting with easy integration into a more complex TCL environment.

Applications Programmers Interface (API) 

As part of playing well with other TCL software, a majority of expect-lite has been encapsulated in a TCL namespace, expectlite (TCL does not permit dash in a namespace name). This prevents procedure- (or functions) and variable-name collisions with other TCL code.

The API includes the following functions, listed in typical order of use:
  • expectlite::_el_init_library
  • expectlite::_el_import_session_ids
  • expectlite::_el_import_const
  • expectlite::_el_buffer
  • expectlite::_el_exec_script

Details & examples of the API

Included in the expect-lite tarball is the file test_el_lib.tcl. The example program, is a hybrid script, part TCL, and part expect-lite. The API functions are listed below in more detail, and are listed without the namespace name: expectlite for brevity.

_el_init_library

Used to initialize the expect-lite library, loads the expect library, and optionally can take a list of expect-lite constants (read-only variables) as name value pairs in the form of var=value, and expect-lite directives.

Example:
_el_init_library "*EXP_INFO IP=10.5.5.5 *DEBUG"

_el_import_session_ids

The TCL program may have previously created expect sessions which would be used in the expect-lite script. Session names are imported into the expect-lite *FORK sessions, and the expect-lite script will have access to use the session names defined by the program.

Since TCL can not pass arrays, the array of sessions is passed as a list (via [array get session]).

Example:
# create spawn sessions and set prompt to identify the session
spawn bash
send "export PS1='0\$ '\n"
set session(default) $spawn_id

spawn bash
send "export PS1='1\$ '\n"
set session(dut1) $spawn_id

_el_import_session_ids [array get session]

_el_import_const

As mentioned earlier, it is possible to pass expect-lite constants and directives via _el_init_library call. However that can only be called once. It may be more desirable to create a loop where TCL variables are imported into expect-lite. The _el_import_const function that does this can be called many times.

Example:
_el_import_const "DUT=mydut *NOFAIL"

_el_import_const "DUT2=thatdut "

_el_buffer

This function is used to read a file into expect-lite's private command buffer space. In the included example test_el_lib.tcl, the TCL file itself is read into _el_buffer. Since any line that does not begin with expect-lite's punctuation characters is ignored, all the TCL in the test program will be ignored.

This function returns a pointer to the private buffer space. This must be passed to _el_exec_script for execution.

Example:
# read this file as expect-lite script, and return pointer to buffer
set cmd_file $argv0
set cmd_list_ptr [_el_buffer $cmd_file]

_el_exec_script

Having prepared the library with the necessary information, this function is the core of expect-lite. It interprets the expect-lite punctuation commands (such as '>', '<'), as well as dereference expect-lite variables. This function returns the following result codes:
  • zero (0) if the expect-lite script passes
  • one (1) if the expect-lite script fails
  • two (2) if the result is unknown (usually abnormal end of the script).
Example:
# call el script exec
set RESULT [ _el_script_exec "" $cmd_list_ptr ]

# Print result of test
switch $RESULT {
0 { puts "\nTest Passed" }
1 { puts "\nTest Failed" }
2 { puts "\nTest Abend" }
}

Changes in behaviour when running expect-lite as a library

The thinking is that when running expect-lite as a Library (aka library mode), one would not be debugging the expect-lite script itself, but rather one's focused on the integration of the program into the TCL environment. Therefore the following functionality is changed compared to how expect-lite runs in standalone mode.
  • *INTERACT is be ignored in library mode
  • *TCL is a method which is ignored during normal expect-lite operation, but in library mode, it enables the calling of native TCL functions from within the embedded expect-lite script. Notes:
    1. *TCL is still line oriented, and should only be used for one line TCL commands, or calls to TCL functions
    2. *TCL has no protection, bad TCL syntax will crash the TCL program
    3. expect-lite timeouts (@number) will not occur on a *TCL line
  • ~include_file is no longer ignored in Library mode (as of v4.6.2). Use *NOINCLUDE to retain v4.1.0 behaviour


19 November 2013
http://expect-lite.sourceforge.net/

this document for version 4.6.2 and above

expect-lite.proj/Docs/expect-lite_future.html0000644000076400007640000001020412562233520022066 0ustar cvmillercvmiller expect-lite Future

greater than

expect-lite


The Future of Automation for the rest of us


What is in the Future?

expect-lite is continuing to be enhanced. The next feature version will be 4.0.x. The focus is on making it even easier to create automated scripts, and debug them.

What will be in 4.0.x? 

The next version will include a big improvement to the IDE:
  • Dependency on TclX will be removed.
  • IDE help display
  • Display of previous and next 1 to 9 lines in the running script
  • Step or sKip through the script line by line in IDE 
  • Paste one or more script lines into the IDE and have them execute (this is a cool feature, since it will automatically dereference any variables in the line)
And improvements are not just limited to the IDE:
  • Directive *NOFAIL, script will not quit upon failure
  • Directive *SHOW VARS will also display constant values
  • Directives can be passed in on the command line

When will it be available?

By end of the 2010, preferably sooner.

What can I do to help? Cygwin needs help.

To fully take advantage of the above IDE features, a more recent version of expect (current is 5.44) is required. However the current cygwin version is 5.24, and many of the cool new IDE features will not work.

Do you have a newer version of expect for cygwin? If so, can you update cygwin.com repository? If not, can you send me the binary, and associated TCL library?

[Update] I have a CVS version (pre-5.45) of expect working in Cygwin. Now I just need help getting into the Cygwin Repository.

Future feature ideas?

The purpose of this peek into the future is to gain your ideas and help. Send them to me <cvmiller at gmail dot com> with 'expect-lite' somewhere in the subject line.

Want to see the Future?

expect-lite has been kept in a git repository since version 3.6.0, the respository is now published at github. Use your git to retrieve it:
git://github.com/cvmiller/expect-lite.git

The next version is called 2expect-lite. Caution: it has not been extensively tested (yet).


2 October 2010
http://expect-lite.sourceforge.net/

this document for version 3.7.1 and above

expect-lite.proj/Docs/expect-lite_tips.html0000644000076400007640000005727612562233520021557 0ustar cvmillercvmiller expect-lite Tips

greater than

expect-lite


Automation for the rest of us

Tips and Techniques: Simplifying the Debugging of expect-lite scripts



Introduction

Over the years of using and improving expect-lite, a few debugging techniques have proven quite useful. The purpose of the document is to provide some additional information to assist the user of expect-lite in debugging scripts, and tips to make expect-lite script writing even easier. Familiarity with expect-lite is assumed, if not, please refer to the expect-lite documentation.

Contents

Some Tips and Techniques for expect-lite:

Interact - setting breakpoints

Interact may be the quickest, easiest, and overall best debugging aid. It is equivalent to setting a breakpoint in the script. Interact is a mode which turns control of the keyboard over to the user, so that one may type directly to the process on the remote host With version 3.5.0 there are two methods to invoke Interact: programmatic, and instant-interact.

Programmatic Interact is called in the script with the following command:
*INTERACT
Expect-lite will pause at this point in the script, and connect the keyboard to the remote session (which may be at a prompt). Any command may be entered and responses observed. Typing '+++' (3 pluses) will return control to the script, and it will continue. This is very helpful for automation assist, allowing the script to perform complicated setup commands, before turning control over to the user for an interactive session.

The other method is instant-interact. This feature no longer requires the tcl package Tclx to be installed. The user can press '^\' (control+backslash) at anytime creating a breakpoint on the fly. This is the easiest, and fastest way to debug a script, dropping the user into the IDE.

Debugging with the IDE

To make debugging of scripts even easier, both methods of interact support the new and powerful expect-lite Integrated Debugger Environment (IDE). Inside the IDE, it is possible to do many things:
  1. Type command directly to the remote host (router, embedded system, Linux box)
  2. Step or sKip line by line through the expect-lite script
  3. Show all expect-lite variables and constants
  4. Show the most recently executed lines, or the next few lines of the script
  5. Paste expect-lite script line(s) into the IDE and have them execute. This is really cool, since it will dereference any variables in the pasted text, or allow you to run just a few lines of script over and over
  6. The IDE can't die, since *NOFAIL automatically enabled while in the IDE.
  7. Type expect-lite command directly while in the IDE, including >, <, $var=, +$var,@n (set timeout).
Stepping, sKipping and Showing
In the above list, #1 is the same as previous versions of expect-lite. Stepping, sKipping, and Showing are new in the IDE (#2, #3, #4). These commands are all two-keystroke commands. The first key is the escape key (or esc) followed by s, k, c, v, e, h and 0 through 9. These keys are not echoed to the screen, nor are they received by the remote host. To represent the key presses [type <esc>h] has been added to the text for completeness.
[type <esc>h]
IDE: Help
Key Action
---- ------
<esc>s Step
<esc>k sKip next step
<esc>c Continue
<esc>v show Vars
<esc>e show Env
<esc>0to9 Show N next lines of script
<esc>-1to-9 Show N previous lines of script
ctrl+D Quit & Exit expect-lite
<esc>h this Help
Showing the lines of the script running up to the breakpoint, the current line, or the next few lines of the script can all be displayed by typing <esc> and a number. If the number is negative, say -3, then the last 3 lines will be displayed. The following example is displaying the next 5 lines of the script:
[type <esc>5]
$ Printing next 5 line(s) of script:
> echo hello
?if 1 == 1 ? %PAU
>> pwd
+$P=\n/home/([a-z]+)
>echo "test_include.txt"
Typing <esc>0 will display the current line in the script:
[type <esc>0]
$ Printing current line of script:
*INTERACT

To exit the IDE and continue the execution of the script type <esc>c  This is the same as typing  '+++'

Typing commands directly into the IDE
In the IDE, expect-lite script commands can be typed directly into the terminal, even assigning variables and displaying them, inside the paused script, for example:
$MYVAR=today
[type <esc>v]
$ DEBUG Info: Printing all expect-lite variables
Var:MYVAR Value:today
Var:junk Value:orbit-root
Var:manarch Value:i386 Const:ppc

>>pwd
pwd
/home/user
Note that variables are printed with any overriding constants.

Pasting into the IDE
Of course, typing is useful, but copy and paste is much easier. Pasting lines into the IDE can be really helpful in debugging a script. For example, you may want to debug a dynamic variable assignment. The script may have the following lines:
>ifconfig
# get IP address of loopback interface
<lo
+$ip_addr=inet addr:([0-9.]+)
This code snippet displays all the interfaces on this machine, expecting lo will clear the capture buffer above 'lo', thus removing the info from the eth0 interface. The dynamic variable will capture any numbers and periods after the words 'inet addr:'

By copying the lines from the script and pasting them into the IDE the terminall will display following:
$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:30:65:98:e5:4a
inet addr:10.1.1.125 Bcast:10.1.1.255 Mask:255.255.255.0
inet6 addr: fe80::230:65ff:fe98:e54a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
...
Interrupt:41 Base address:0x6c00

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
...
Assigned Var:ip_addr=127.0.0.1
$
And of course, code blocks can be pasted into the IDE as well. Take care to paste the entire code block to get the desired result. Pasting the $i=0 is important, since it initializes the counter in the while loop.
; === while loop
$i=0
[ $i < 3
>echo "hello $i"
<hello $i
+$i
]
Pasting in the modern age
As of 4.8.0  some additional constraints have been added when pasting into the IDE, as the IDE was interfering with typing to the remote host. To prevent interference with typing to the remote host, you should start your paste with of the following lines:
  • variable assignment ($var=value)
  • comment (single semi colon)
  • send (>)
By starting your paste with one of these lines, it triggers the IDE to treat the additional lines as a paste rather than typing to the remote host.

Additionally, there are few subtleties which the user should be aware when typing or pasting expect-lite lines into the IDE:
  • variable assignment must include equal sign e.g. $var=
  • comment lines must have a space after the semi-colon ; this comment
  • conditional statements must have the english word 'if' when pasteing e.g. ?if this != that?
    • conditionals do not require the optional 'if' when running in a script, only applies to pasting the first line


IDE, It lives!

It is possible to paste in lines which would normally fail the script. However getting kicked out of the script while one is debugging is not only irritating but not all that useful. For example, using similar script lines to above:
>ifconfig
<eth2
Since there is no eth2 interface on this machine the script snippet will fail. However, the *NOFAIL directive is automatically enabled inside the IDE, there pasting the snippet results in:
$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:30:65:98:e5:4a
inet addr:10.1.1.125 Bcast:10.1.1.255 Mask:255.255.255.0
...
FAILED COMMAND:
Expect Failed:eth2
$

Instead of the expect-lite exiting, and declaring the script has failed, it remains in the IDE (at the *INTERACT, or breakpoint), ready to receive another command.

Running to Completion

The normal operation of expect-lite is to stop with any failure. However, this may not always be the desired behaviour. Using the *NOFAIL directive, will prevent the expect-lite script from stopping prior to completion. The directive *NOFAIL can be placed in the script, or on the command line (as well as any other directive).

expect-lite will still detect failures and report them at the end with the message:
##Overall Result: FAILED (*NOFAIL on)
Once *NOFAIL has been directed, it remains on for the rest of the script. Conceptually it is the opposite of *FAIL, which fails the script immediately (if *NOFAIL isn't set).

Finding In... Verbose

Since most expect-lite scripts are composed of > and < lines, it can be difficult to understand why expect-lite isn't finding the desired text. Using the -vv or --verbose option (in version 3.1.4 or later) will display the string that is to be matched (find) and the entire string that is being searched (in).

For example, for the given expect-lite code:
>cat $tmp_file
<Proto \[LAN\]Addr:Port => Addr:Port \[WAN\]Addr:Port <= Addr:Port
<6[ \t]+[0-9a-f:]{11,14}[ \t]+[0-9a-f]{8}:22
With the --verbose option, the output will appear with the additional lines:
cat /proj/regression/tmp/junk
Dec 31 1969 19:43:12:025952:INFO :CLI :cli.c:2945:_cli_handle_short_cmd:
Execute command: "fwdstat".
Proto [LAN]Addr:Port => Addr:Port [WAN]Addr:Port <= Addr:Port
6 c0a85001:41696 c0a81401:22 c0a81401:22 c0a81402:32770

find<<Proto \[LAN\]Addr:Port => Addr:Port \[WAN\]Addr:Port <= Addr:Port>>
in<<cat /proj/regression/tmp/junk
Dec 31 1969 19:43:12:025952:INFO :CLI :cli.c:2945:_cli_handle_short_cmd:
Execute command: "fwdstat".
Proto [LAN]Addr:Port => Addr:Port [WAN]Addr:Port <= Addr:Port>>

find<<6[ \t]+[0-9a-f:]{11,14}[ \t]+[0-9a-f]{8}:22>>
in<<
6 c0a85001:41696 c0a81401:22>>
Both the 'find' and 'in' text are wrapped in << >> to show any line feeds. The 'find', if successful, will almost always be at the bottom of the 'in' text. Often when there is a unexpected failure, the  '<' is defined too broadly, and expect-lite has matched an unexpected piece of 'in' text. (see Define '<' narrowly)

As of expect-lite version 3.1.4, -vv or --verbose will also display 'find and 'in' for dynamic variable capture, thus providing a bit more information to assist in debugging this feature as well.

As of expect-lite version 3.5.0, -vv or --verbose will display all warnings and debug information (including user defined prompt debug info)

Showing Variables, Values & Constants with *SHOW VARS

Sometimes when troubleshooting a script, it is really useful to display the value of an expect-lite variable. The easiest method to display a variable is to use the printable comment ';'  For example, there is a variable named '$max', by adding the following line to the script, $max will be dereferenced and displayed:
; The value of max is:$max
The above method works well for a few variables, but it may be necessary to view all the expect-lite variables. In previous versions of expect-lite, a script (show_vars.inc) was required to view all variable values. As of version 4.0.x, the expect-lite directive: *SHOW VARS now displays variables, values, and any overriding constants.

All variables can now be displayed by using the line:
*SHOW VARS
The output will appear like the following:
expect-lite directive: *SHOW VARS 
DEBUG Info: Printing all expect-lite variables
Var:arg0 Value:test_script.elt
Var:count Value:14
Var:mac_da10 Value:00:7F:DE:6A:FF:FA Const:00:30:65:98:e5:4a
Var:mac_da11 Value:88:45:3D:2A:95:63
Var:mac_da12 Value:38:8B:50:49:AE:0D
Var:mac_da13 Value:38:E4:EB:0C:DE:4B

*SHOW VARS can also be used with *INTERACT and instant-interact to view the values all assigned variables, however, <esc>v performs the same action and is less typing.

Showing Environment with *SHOW ENV

The goal is to keep it simple. However, expect-lite has matured enough that is may be hard to keep track of which directives are enabled, and how many loops have occurred in the script. To make the script writer's job a little easier, all that info is now printed with the directive *SHOW ENV.
$ *SHOW ENV
DEBUG Info: Printing expect-lite directives/environment
Environment: Value:
CURRENT_FORK_SESSION default
DEBUG off
DVPROMPT on
EOLS LF
EXP_INFO on
INFINTE_LOOP_COUNT 5000
INFO on
LOG off
LOG_EXT .log
NOFAIL on
NOINCLUDE off
NOINTERACT off
TIMESTAMP off
USER_DEFINED_PROMPT .*$ $
WARN on
fuzzy_range 10
timeout 2
EL_CONNECT_METHOD ssh_key
EL_REMOTE_HOST localhost

The directives are listed in sorted order, fuzzy expect range, and timeout are printed. Then finally any Shell environment variables are printed.

The *SHOW ENV command can be added to the expect-lite script to display the above. This can aid in debugging overnight regression logs, or even supporting others running your scripts. The expect-lite environment can also be displayed from within the IDE by typing <esc> e.

Define '<' narrowly

Do not define '<' too broadly. For example, DO NOT use the following:
<\n.*
The above defines 0 or more of any character after a newline. This will match just about anything, and more than likely not what is intended.

Instead use a more specific '<'. If the expected string is only composed of numbers at the beginning of a line, use:
<\n\d+
Use with the --verbose option to see what is being matched, and to assist in refining the '<' statements.

Decreasing the log chatter

After one's scripts are succesfully debugged, it may not be desireable to see all the log chatter which expect-lite produces, such as warnings, conditional reports, dynamic variable assignments. This chatter can be reduced by using the expect-lite logging directives at or near the beginning of the script, such as:
*NOWARN
If while debugging the script, it is desirable to see the additional logging info (chatter), it can be turned on via the command line with the -v parameter:
expect-lite -v r=myhost c=myscript

Removing Colour from output

In an automated environment, it is probably not desirable to have ANSI color sequences embedded in the logs. Although it is possible to use the expect-lite directive *NOCOLOUR in each script to turn off colour, there is an easier way. Define the terminal type to a dumb terminal, such as tty.
export TERM=tty
expect-lite will detect the dumb terminal type and turn off colour output automatically.

Or as of version 4.0.x, *DIRECTIVES can be placed on on the command line, therefore it is possible to turn off colour on the command line:
expect-lite -r myhost -c myscript *NOCOLOUR

Adding Web Colour to output

Depending on your regression reporting engine (e.g. Jenkins), it may be desirable to display colour but in a web browser such as Firefox. expect-lite looks for a special terminal type, web, and enables HTML colour codes in the output.

export TERM=web
Merging expect-lite and the web is still considered experimental. Currently there is no directive equivalent.

General Tips

Here are some simple tips when script writing:
  • Use reasonable timeouts, if 30 seconds is needed to get a response, set the timeout at 45 or 60 seconds, not 600.
    • There is no cost to changing the timeout, timeout values can also be variables
  • Beware of expect-lite using regex, when creating lines like: <0.005 secs (5 micro secs)
    • The parentheses is used by the regex engine, instead escape these characters: <0.005 secs \(5 micro secs\)
    • or use '<<' which does not use regex, and does not require escaping: <<0.005 secs (5 micro secs)
  • Use the expect character '<' or '<<' often. Check for valid results when possible. A script which expects nothing will never fail!
  • Use printable comments ';'  and ';;' often. Think of it as writing a note to oneself, it will make reading log files much easier. As of version 3.7.0 printable comments will be coloured blue (this is user configurable).
  • Variable assignments use no spaces e.g. $var=value. Note no spaces around the equals sign, this permits leading spaces in the value such as $var=  myvalue

Summary

By using these troubleshooting aids, it should be even easier to write and debug expect-lite scripts. Feel free to send me any tips. cvmiller at gmail dot com

Why Expect-lite

Expect-lite was written to create quick and easy automation of repetitive tasks.



15 January 2015
http://expect-lite.sourceforge.net/

this document for version 4.8.0 or later

expect-lite.proj/Docs/keycap_200.jpg0000644000076400007640000001120612562233520017725 0ustar cvmillercvmillerJFIFHHExifMM*C  !"$"$C> !1Q"2Aaq34Sr#$BRCbsDcTA!1Q ?Z@@@ BM( r@\.P( o4@  Br]I ɆFa/0ѿhEѿ( }@qq p@כ @t;Xc:Jinc}k5xOF'!OFM7`3O 0s~ 5?@p񂞗 uR t OG:,31 z0Ӥ?m0쇪a `b$2yi{ju BlNM++ѡLQ\H:^j+4g5k'^"$4_4 t1DuU񕦛Lۓ\>euBÏ.2H1 ]P8\ 1;).`AЂ,@@k U(EYw]~Fwwu#s9Nk]JC%z%pm fB9{)A9ݺ Ҟi_WE!pퟄ1 FYxFgYa[E y`-=UaĈ(@i9_"ns{!'&t:~6O\NZAslK(,Y/="m '<52ַ.ƯԘj,H$*Z$i>rQI\~65(x Xjr G$j 8-s3מc+0QXqa!vsum0ɈTBͅ0s-m b c@ؐ.4Ȁ@ #{Uq$U[<6p 厫QJ?]~P78RKGCP8dHVTj<0Q5jM6E[gu*23TA|6-p|Y.5'|DvC̫:xCR V .M @]Ʊًg+e@$Du5(5i^PJqAoBmA>WrຨjQji~J6.V]P T NhN@ [g4:KCa8,sS$fS䠾4xcFemU݅(oS$>5h^f.7YRkCꯉ}F?cAU8CVkѨ&As_=I"Z Rƫ*վjQj-- PA6V *ZQ$9Ql(lyɦmh GҲҴrcNo%usj0OT['Oz=7VI5荟`zvkDiČ.I1mYR@Q✧rj^R2yokP ZELdLw=yv󕞚`ԮU@h5(@e(ݮordTFM*\Y`Bt@6-bISĕ'Fyf_&wՃީ^{f:x"p?)Xw9AaIӥ 7%r]$@ B QZ}VOkQyJPu5(}"'PLwyv󕞚U\~UB_5(J{?%(*lF=pBUew U%ыÿeU<ŲY ֵXjV!\I衡dqH`.6H Mes]҉>ڥR6b{_H@ ?C깊F+:Nc.ƺ-դ[$j &yu{Y騣5%T RdCSFBU B F+49K;=6è+&XOzD  hkn-3XmӬtl7Fq|gy^ VZp5'FD_3bi#QV%Nu5h"'PLoiEaζIY鸣ຨsNU(I3LUF'9IXNs0{'9/XAUa ɎvݜǮeJ4bpY^y~'.ihL kE\ @5@~CAFVRP}X]b-}Y@ 5طG7mܪCNAp!T+uh-Y1SF]A͠z&361&/lVbo.+M&{!iYq5k%`05Ёp\.=s^ YR DР^ŠApVSWkPU HB PCAv KV*ϚZvtPgV* ֽhs\,AЄj;37%VBh|oˌ'6KD/3Ft٦=򭖘s`Ԙ:ɶW.Y֮*H{ܡ}WAÉxB'XŚ?U:P ݳ×zK! $^D ECtG֦U3=f>oz>2 @kѾ nNi?L惜xn{w+e&PY͐sk]cG0h`uinJț xV7=9M/Z'(C@hkhDŽE)HQr ;G]cnA5iS@ނ4 #6xQ$u+BiWFV PNnH48Ez9f=R:,&qop,o\kK[ ! S i#R*JFV\Di֭nfX{#J$~_R?r/USd4ztܩQHVo=HMTBɹh@/Fe_9FaQFxTZ?1=6rtJ(// 옚PpnpO"9> kt[G[(, ;Hb.nꜛwZ+kAH&O~t9h\?B] wb@fD:Cl$xdJ\QB\k 4@f VZ!LK4kcÎ(`4E#@d GD8 :$p@d7 @E26TpA '‡n-*2HM=͚{3 Q*;H[[[[[[Qd5@sQ}8K7p expect-lite

greater than

expect-lite


Automation for the rest of us


What is it?

expect-lite is an quick and easy command line automation tool.

Written in expect, it is designed to directly map an interactive terminal session into an automation script. expect-lite scripts use special character(s) at the beginning of each line to indicate the action. Basic expect-lite scripts can be created by simply cutting and pasting text from a terminal window into a script, and adding '>' '<' characters. No knowledge of expect is required!

Includes a Powerful Debugger with breakpoints, step/skip, copy/paste expect-lite lines right into a running script.

Structured programming via Code Blocks, enables easy to create while loops, and conditionals (if statements).

Full IPv6 support, using telnet or ssh over IPv6, and IPv6 addresses in the script.

Expect-lite is targeted at the verification testing environment, and will produce a Pass/Fail result at the end of the script. However, its use is not limited to this environment and can be used anywhere a text-based interface needs a bit of automation.

What is it for? 

A simple to use automation tool to do:
  • Functional, System, Regression Testing.
  • White or black box Testing.
  • Automated Router Configuration.
  • Compiler validation.
  • etc.

What New?

Latest version 4.3.0 improvements include:
  • User defined help (run your script with a -h)
  • Pass include files parameters (e.g. ~login.inc user=root)
  • *NOINTERACT directive (useful for quick regression scripts)
  • ##Include Result: FAIL message (for quick regression scripts)

The main purpose is keep it simple. However, the advanced features allow pretty creative scripting.

The central ideas behind the design are:

  • Just keep it simple and portable - it runs on Linux, Mac OS X, *nix, and Windows(with cygwin).
  • No syntax errors
  • Make the automator's life easier.

Examples

Check the IP address of the localhost

>ifconfig
<192\.168\.1\.1
>ip -6 addr show
<2001:db8::f00d

ssh to a remote host

>ssh root@host-021
<assword:
>>secret_password
# issue a command once logged in
>ls
>exit
While loops using code blocks
$i=1
[ $i < 5
>echo "hello times $i"
<times $i
+$i
]

expect-lite includes over 25 example scripts covering topics such as: if statements, looping, multiple sessions, random number generation, and more.

Where to get it?

The most recent version is always available on SourceForge:

Download expect-lite



24 April  2012
http://expect-lite.sourceforge.net/

this document for version 4.3.0 and above

expect-lite.proj/Docs/expect-lite_simple.html0000644000076400007640000001365112562372076022070 0ustar cvmillercvmiller expect-lite

greater than

expect-lite


Automation for the rest of us


What is it?

expect-lite is a mature, quick and easy command line automation tool.

Written in expect, it is designed to directly map an interactive terminal session into an automation script. expect-lite scripts use special character(s) at the beginning of each line to indicate the action. Basic expect-lite scripts can be created by simply cutting and pasting text from a terminal window into a script, and adding '>' '<' characters. No knowledge of expect is required!

Includes a Powerful Debugger with breakpoints, step/skip, copy/paste expect-lite lines right into a running script.

Structured programming via Code Blocks, enables easy to create while loops, foreach loops and conditionals (if statements).

Full IPv6 support, using telnet or ssh over IPv6, and IPv6 addresses in the script.

Expect-lite is targeted at the verification testing environment, and will produce a Pass/Fail result at the end of the script. However, its use is not limited to this environment and can be used anywhere a text-based interface needs a bit of automation.

What is it for? 

A simple to use automation tool to do:
  • Functional, System, Regression Testing.
  • White or black box Testing.
  • Automated Router Configuration.
  • Compiler validation.
  • etc.

What New?

Latest version 4.9.0 improvements include:
  • Native Sleep support with mili-second resolution
    • Use a colon to indicate length of sleep, e.g. 10.5 seconds
      :10.5
    • Progress dots to show script is sleeping, including logging
      Sleeping: ....+....10.
    • Sleep value can be a variable
      :$sleeper
  • Progress dots added to expect lines (<, <<, ~<) to provide better feedback on how long the script waited for expected value
    • information output can be suppressed with *NOINFO directive

The main purpose is keep it simple. However, the advanced features allow pretty creative scripting.

The central ideas behind the design are:

  • Just keep it simple and portable - it runs on Linux, Mac OS X, *nix, and Windows(with cygwin).
  • No syntax errors
  • Make the automator's life easier.

Examples

Check the IP address of the localhost

>ifconfig
<192\.168\.1\.1
>ip -6 addr show
<2001:db8::f00d

ssh to a remote host

>ssh root@host-021
<assword:
>>secret_password
# issue a command once logged in
>ls
>exit
While loops using code blocks
$i=1
[ $i < 5
>echo hello times $i
<times $i
# sleep 2.2 seconds
:2.2
+$i
]
Conditional using code blocks
? $IP == 2001:db8::f00d ? [
>echo future of the internet is here
]::[
>echo time to upgrade to IPv6
]

expect-lite includes over 25 example scripts covering topics such as: if statements, looping, multiple sessions, random number generation, and more.

Where to get it?

The most recent version is always available on SourceForge:

Download expect-lite



15 August 2015
http://expect-lite.sourceforge.net/

this document for version 4.9.0 and above

expect-lite.proj/Docs/js-side-menu.js0000644000076400007640000000227312562233520020230 0ustar cvmillercvmiller// external js code // print array of lines, which becomes the side menu menu_lines = [ '' ,'' ]; function print_menu_lines (lines) { var line_break = '
'; for (var line in lines) { document.writeln(lines[line]); } } print_menu_lines(menu_lines); document.writeln("

Celebrating 10 years of creating quick solutions

") // simple solutions since 2005 expect-lite.proj/Docs/vbar.gif0000644000076400007640000000013012562233520017001 0ustar cvmillercvmillerGIF89a!,@Ik;expect-lite.proj/Docs/expect-lite_license.html0000644000076400007640000000720312562233520022203 0ustar cvmillercvmiller expect-lite license

greater than

expect-lite


Automation for the rest of us


BSD-Style License

Copyright (C) Craig Miller 2008-2015
Copyright (C) Freescale Semiconductor, Inc. 2005-2007

See the  COPYING for information on usage and redistribution
of this file, and for a DISCLAIMER OF ALL WARRANTIES.

License (full text)

Copyright (C) 2008-2015, Craig Miller
Copyright (c) 2005-2007, Freescale Semiconductor, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the Freescale Semiconductor nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


expect-lite.proj/Docs/el.css0000644000076400007640000000100612562233517016503 0ustar cvmillercvmiller body { max-width: 900px; text:"#000000" ; bgcolor:"#ffffff" ; link:"#0000ee" ;" vertical-align:top; vlink:"#551a8b"; alink:"#ff0000" ; } pre { background-color: #f0f0f0; font-size: 14px; } h1 { font-family: "Lucida Sans Unicode"; font-size: 36px; font-weight: bold; color: #000000; } h2 { font-family: "Lucida Sans Unicode"; font-size: 20px; font-weight: bold; color: #999999; } .page { font-family: "Lucida Sans Unicode"; font-size: 16px; } .mail { font-size: 10px; text-align: right; } expect-lite.proj/Docs/expect-lite_ols.html0000644000076400007640000001451712562233520021364 0ustar cvmillercvmiller expect-lite at the Linux Symposium

greater than

expect-lite


Automation for the rest of us


What is it?

expect-lite is an quick and easy command line automation tool.

Written in expect, it is designed to directly map an interactive terminal session into an automation script. expect-lite scripts use special character(s) at the beginning of each line to indicate the action. Basic expect-lite scripts can be created by simply cutting and pasting text from a terminal window into a script, and adding '>' '<' characters. No knowledge of expect is required!

The main purpose is keep it simple. However, the advanced features allow pretty creative scripting.

What is New since Linux Symposium 2010?

The new features include:

  • Color (3.7)
    • *EXP_INFO - displays expected value found
  • IDE (4.0)
    • Powerful Debugger with breakpoints, step/skip, copy/paste expect-lite lines right into a running script.
    • *TIMESTAMP > commands
  • Library Release (4.1)
    • use expect-lite as a TCL library
  • Code blocks (4.2)
    • While Loop
    • Multi-line if statements
    • Full IPv6 support
  • User Defined help (4.3)
    • Making your script more user friendly
    • Include file improvements - simple regression
      • *NOINTERACT - does not stop at breakpoints
  • Native Logging (4.4)
    • Log everything to a file, natively
    • *LOG *NOLOG
  • Code blocks - else statement (4.5)
    • Foreach Loops with code blocks (4.6)
    • String Math: search/replace, concat, remove
  • Fuzzy Expect (4.7)
    • Expect an approximate value e.g. 11 is about 10

Download the Linux Symposium Presentations 

The Linux Symposium Presentations are in PDF format:

Where to get it?

The most recent version is always available on SourceForge:

Download the latest version

Also expect-lite is even easier to install as part of the following distributions:

Examples

Check the IP address of the localhost

>ifconfig
<192\.168\.1\.1
>ip -6 addr show
<2001:db8::f00d

ssh to a remote host

>ssh root@host-021
<assword:
>>secret_password
# issue a command once logged in
>ls
>exit
While loops using code blocks
$i=1
[ $i < 5
>echo hello times $i
<times $i
+$i
]
Conditional using code blocks
? $IP == 2001:db8::f00d ? [
>echo future of the internet is here
]::[
>echo time to upgrade to IPv6
]

expect-lite includes over 25 example scripts covering topics such as: if statements, looping, multiple sessions, random number generation, and more.



14 July 2014
http://expect-lite.sourceforge.net/

this document for version 4.7 and above

expect-lite.proj/expect-lite0000755000076400007640000051462712564335303016672 0ustar cvmillercvmiller#!/usr/bin/env expect ################################################################################## # # Copyright (C) 2008-2015 Craig Miller # # Copyright (C) 2005-2007 Freescale Semiconductor, Inc. # # See the file "COPYING" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # Distributed under BSD-Style License # ################################################################################## # # # Expect-lite # Script logs into Remote-host, sends command file, while validating commands # fails if validation fails, returns code 1 (0=passed) # # by Craig Miller cvmiller@gmail.com 19 Jan 2005 # # # Requires Expect version supported 5.42.1 and later (although earlier versions may work) # # ################################################################################## # # The user may want to customize the following variables & procs to suite one's needs # # # Encapsulate expect-lite variables in a namespace to prevent collisions with other apps namespace eval expectlite { # echo version in usage variable version "4.9.0" #set starting expect timeout set ::timeout 10 set _el(exp_timer) $::timeout # EL_LIBRARY when set, places expect-lite in library mode, # used for TCL programming calling expect-lite functions directly # see documentation for more info # Normally, this would be UNSET (or commented out) #set EL_LIBRARY 1 # infinite_loop protection - Max number of looping permitted # Protects against infinite loops by decrementing this number # when value is Zero, _el_buffer_search will return 'not found' (-1) # typically this should be set in the range of 5000-10000 variable _el_infinite_loop 5000 # hardcoded login values - only used for telnet, and ssh logins variable user "root" variable pass "" # User is now used by ssh_key method as well. If user is blank then the default # user will be used (the user running the script). However if $user is defined # then ssh_key will use the following command: ssh $user@$host variable user "" # Print Warnings to stdout (when set to 1 = TRUE, 0 = FALSE) variable WARN 1 # Print Info messages to stdout (when set to 1 = TRUE, 0 = FALSE) variable INFO 1 # Print Expect Info messages to stdout (when set to 1 = TRUE, 0 = FALSE) variable EXP_INFO 0 # Select remote shell to spawn after logging into remote host variable remote_shell "bash" variable remote_shell "" # Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture # 100 ms is a good value for a local LAN, 200 ms if running across high speed internet variable delay_wait_for_host 100 # connects to login host, and logs in as $USER # # Choose one login method here # #set connect_method "telnet" #set connect_method "ssh" #set connect_method "ssh_key" variable connect_method "none" # Accept SSH host keys variable connect_ssh_accept_host_key "-o StrictHostKeyChecking=no" variable connect_ssh_accept_host_key "" # Path to telnet (helps in cygwin environments) variable _el_telnet "/usr/bin/telnet" # set the user configurable prompt to something sane set ::expectlite::_el(prompt) ".*\$ $" # set global color for comment ; or ;; lines # select one of the following: none, blue, ltblue, gray, ltgray, cyan, black, pink, purple variable _el_comment_color ltblue # End of Line Sequence (eols) - typically \n or \r\n # some devices must have a CRLF at the end of line in order to respond # This is also controlled by directive *EOLS LF|CRLF variable _el_eols "\n" # Set dynamic var capture uses prompt or not (default=yes, use prompt) variable DVARPROMPT 1 #################################################################################### # # Vars & Procs below here should not require customization # # # # Provide info for library mode # package provide expect-lite 4.0 # # Initialization of Global Variables # proc _el_init_globals { } { #set ::expectlite::_el_timeout to hold value of timeout (used to preserve value of timeout) variable _el_timeout $::timeout #set ::expectlite::the expect Match Buffer really large match_max -d 10000 #Create Debug Log output == 1, no log ==0 variable DEBUG_LOG 0 # declare array user_namespace (for user vars) set ::expectlite::user_namespace(0) 0 # declare array cli_namespace (for cli passed constants) set ::expectlite::cli_namespace(#) " " # declare array cli_namespace (for cli passed constants) set ::expectlite::cli_namespace(EL_CONNECT_METHOD) "none" # declare global array _el (for internal expect-lite vars) set ::expectlite::_el(0) 0 # declare global el STOP variable, used to stop paste lines set ::expectlite::_el(STOP) "RUN" # clear NOFAIL flag 1=test should have failed set ::expectlite::_el(test_failed) 0 # clear native expect lines list set ::expectlite::_el(_el_lines) {} # initialize expect line - used to read buffer set ::expectlite::_el(line) "" # clear ide paste lines flag set ::expectlite::_el(ide_paste_lines) 0 # initialize the command file name set ::expectlite::_el(cmd_file) "" # initialize the fuzz value - used for fuzzy expect '~<' set ::expectlite::_el(fuzz) 10 # debugging aid: turn on to display match string and expect buffer variable DEBUG 0 # timestamp on send: turn on to display timestamp when sending > or >> variable TIMESTAMP 0 # keep script running to end: turn on to never fail test variable NOFAIL 0 # clear NOINTERACT flag 0=allow interact, >0 skip interact variable NOINTERACT 0 # clear NOINCLUDE flag 0=allow include files, >0 skip include files # this is backward compatibility option for 4.1 library behaviour variable NOINCLUDE 0 # clear LOG flag 0=no log, 1 logging variable LOG 0 # global constant for timeout_multiplier mode variable timeout_multiplier "timeout_multiplier" # global constant for script name aka arg0 variable arg0 "arg0" # global flag show_help - displays help if set variable SHOW_HELP 0 # set ::expectlite::global fork count (for multiple sessions) to 0 set ::expectlite::_el(fork_count) 0 # set ::expectlite::global fork stack to blank set ::expectlite::_el_fork_stack {} # set ::expectlite::global fork id list to blank set ::expectlite::_el_fork_id_list { } # set ::expectlite::default FORK session set ::expectlite::_el(fork_current) "default" # set ::expectlite::current FORK session variable _el_current_session "" # set ::expectlite::default fork_context to default end-of-line-sequence (eols) set ::expectlite::_el_fork(default,eols) $::expectlite::_el_eols # # Scripts (aka Command files) are kept in buffers for random access, and looping # Buffers are global, and are referenced by a "stack" number, the stack number allows multiple buffers to exist # # stack which contains list of valid buffers set ::expectlite::_el_buf(stack) "0" # buffer which contains help text set ::expectlite::_el_buf(help) {} # buf pointer - contains line number of buffer set ::expectlite::_el_buf(0,ptr) "0" # block line stack. used when reading into buffer blocks of lines set ::expectlite::_el_buf_block_stack {} # expect-lite key characters (first char in expect-lite script) variable _out ">" variable _out_nowait ">>" variable _in "<" variable _in_noregex "<<" variable _in_fuzzy "~<" variable _not_in "-<" variable _timeout "@" variable _sleepchar ":" variable _exec "!" variable _stdout_comment ";" variable _stdout_comment_nobuf ";;" variable _include "~" variable _include_fail "\\\*~" variable _setvar "+" variable _var "\$" variable _cond_regex "\\\?" variable _cond "?" variable _cond_else "::" variable _label "%" variable _incr_var "\\\+\\\$" variable _decr_var "\\-\\\$" # cli Parameter Initialization variable remote_host "none" variable cmd_file "" variable user_dir "" # default logging extension variable el_log_ext ".log" # set ::expectlite::the default user configurable prompt to something sane set ::expectlite::_el(default_prompt) ".*\$ $" # set ::expectlite::ANSI colors for colored output set ::expectlite::el_color(red) "\033\[1;31m" set ::expectlite::el_color(blue) "\033\[0;34m" set ::expectlite::el_color(ltblue) "\033\[1;34m" set ::expectlite::el_color(black) "\033\[0;30m" set ::expectlite::el_color(cyan) "\033\[0;36m" set ::expectlite::el_color(gray) "\033\[1;30m" set ::expectlite::el_color(ltgray) "\033\[0;37m" set ::expectlite::el_color(green) "\033\[0;32m" set ::expectlite::el_color(yellow) "\033\[0;33m" set ::expectlite::el_color(purple) "\033\[0;35m" set ::expectlite::el_color(pink) "\033\[1;35m" set ::expectlite::el_color(nocolor) "\033\[0m" set ::expectlite::el_color(left_angle) "<" set ::expectlite::el_color(none) "" # set ::expectlite::INFO color variable _el_info_color green # set ::expectlite::WARN color variable _el_warn_color yellow # set ::expectlite::ERROR color variable _el_err_color red # set ::expectlite::debug color variable _el_debug_color gray # el_exec vars variable comment_line "" variable timeout_line "" # # Expect Signal Handler, which checks for broken stdout pipe # Default signal is SIGPIPE # # trap { catch { puts stderr "\nERROR:Broken Pipe\n" } exit 2 } SIGPIPE # # Expect Signal Handler, checks ^C and exits except inside an IDE paste # Default signal is SIGINT # # trap { if { $expectlite::_el(ide_paste_lines) } { catch { puts stderr "\nPress ^\\ to interupt... returning to instant-interact\n" } # flush the paste buffer catch { expectlite::_el_buffer_stack_clear $expectlite::_el_buf(stack) } error set expectlite::_el(STOP) "STOP" expectlite::instant_interact_sig } else { catch { puts stderr "\nexpect-lite: Interrupt received, exiting...\n" } exit 2 } } SIGINT # # Expect Signal Handler, which places user into instant-interactive(tm) session # Default signal is SIGQUIT or ^\ # # trap { # check if app has output redirected using istty() if {[catch {fconfigure stdout -mode}]} { puts stderr "expect-lite: Warning: Output is redirected from tty.\n The script quit unexpectantly.\n" } # twiggle timeout, so that control is passed back to user #puts "twiggleing timeout" set _tm_out $::timeout set timeout 3 if { $expectlite::_el(ide_paste_lines) } { catch { puts stderr "\nreturning to instant-interact...\n" } # flush the paste buffer catch { expectlite::_el_buffer_stack_clear $expectlite::_el_buf(stack) } error set expectlite::_el(STOP) "STOP" } expectlite::instant_interact_sig #puts "restoring timeout" set ::timeout $_tm_out } SIGQUIT } # # Removes colour if terminal type is not xterm, vt100, cygwin # # proc check_term_type { } { global env upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::el_color el_color upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color #disable global comment color if unknown if { [lsearch [array names el_color] $_el_comment_color] == -1 } { set _el_comment_color none } if { [catch { switch -glob -- $env(TERM) { "xterm" - "xterm-color" - "vt100" - "vt220" - "ansi" - "cygwin" { # keep colors as set globally set el_color(left_angle) "<" } "www" - "web" - "WEB" - "Web" { # set colors to HTML values set el_color(red) "" set el_color(blue) "" set el_color(ltblue) "" set el_color(black) "" set el_color(cyan) "" set el_color(gray) "" set el_color(ltgray) "" set el_color(green) "" set el_color(yellow) "" set el_color(purple) "" set el_color(pink) "" set el_color(nocolor) "" set el_color(left_angle) "<" } default { # set INFO color set _el_info_color none # set WARN color set _el_warn_color none # set ERROR color set _el_err_color none # set global color set _el_comment_color none } } } \ error ] } { puts "Warning: No Terminal Type defined: $error" # set INFO color set _el_info_color none # set WARN color set _el_warn_color none # set ERROR color set _el_err_color none # set global color set _el_comment_color none set el_color(left_angle) "<" } } # # Wraps puts in selected global colour # # proc cputs { str {l_color ""} {newline ""}} { upvar expectlite::el_color el_color upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::LOG LOG proc protect_puts { str } { upvar LOG LOG upvar newline NL if {$NL != "-nonewline"} { # catch stdout errors and quit if { [catch { puts $str } error] } { puts stderr "ERROR:$error" exit 1 } # Log to file if { $LOG } {send_log "$str\n"} } else { # catch stdout errors and quit if { [catch { puts -nonewline $str } error] } { puts stderr "ERROR:$error" exit 1 } if { $LOG } {send_log "$str"} } } if {$_el_comment_color == "none"} { # use no color protect_puts $str } elseif { $l_color != "" } { # use supplied color protect_puts "$el_color($l_color)$str$el_color(nocolor)" } elseif {$_el_comment_color != "none"} { # use global color protect_puts "$el_color($_el_comment_color)$str$el_color(nocolor)" } } # # Interact help # # # proc interact_help { } { send_user "\n" send_user "IDE: Help\n" send_user " Key Action\n" send_user " ---- ------\n" send_user " s Step\n" send_user " k sKip next step\n" send_user " c Continue\n" send_user " v show Vars\n" send_user " e show Env\n" send_user " 0to9 Show N next lines of script\n" send_user " -1to-9 Show N previous lines of script\n" send_user " ctrl+D Quit & Exit expect-lite\n" send_user " h this Help\n" #send_user "\n" return } # # # Actual Signal Handler, which places user into instant-interactive(tm) session # Default signal is SIGQUIT or ^\ # This function is also called by *INTERACT, providing similar functionality # proc instant_interact_sig {} { global expect_out errorInfo timeout upvar expectlite::remote_host remote_host upvar expectlite::_el _el upvar expectlite::DEBUG DEBUG upvar expectlite::NOFAIL NOFAIL upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_eols _el_eols upvar expectlite::_el_buf _el_buf upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color # return if called during a IDE paste if {$_el(ide_paste_lines)} { return } # change user message depending on how the function is called if { $_el(line) != "*INTERACT" } { # called by user cputs "\n\n Press '+++' to end instant-interact & return to script \n\n" $_el_info_color } else { # called by script *INTERACT cputs "\n\n Press '+++' to end interact session & return to script \n\n" $_el_info_color } # do not allow script to fail during IDE incr NOFAIL protected_send "$_el_eols" # preserve script fork session push_session_id $_el(fork_current) set restart_interact 1 # restart interact if *FORK is called to set to new spawn_id # Check that expect version is supported, if not issue warning if { [exp_version] < "5.42.0" } { cputs "Warning: Paste feature requires Expect version 5.42 or later (but using [exp_version])" $_el_err_color cputs " See Cygwin documentation on http://expect-lite.sf.net/ on upgrading expect\n" $_el_err_color protected_send "$_el_eols" } # restore global timeout, if in the middle of something set _el(exp_timer) $timeout while {$restart_interact} { # Interact session connects user to remote session, and also: # Interprets expect-lite commands and directives (as of 4.0) # ensure in RUN mode set expectlite::_el(STOP) "RUN" # reset paste lines flag set _el(ide_paste_lines) 0 if { [catch { interact { -re {\+\+\+|^\x1b\x63|^`c} { #DEBUGGER '+++' or .c to exit interact session, continue script set restart_interact 0 set _el(ide_paste_lines) 0 return } \004 { # ^D exit interact and expect-lite puts "\nExiting interact & expect-lite.\n" exit } -reset \007 { # ^G show lines with meta-data puts "Current Stack---->$_el_buf(stack)" _el_buffer_show 20 $_el_buf(stack) 1 send "\n" #puts "Infinite loop count: $expectlite::_el_infinite_loop" return } -re {^(\x1b|`)(s|k)} { #DEBUGGER .s=Next Step, k=skip step # determine next or skip step set param "s" ; # set default to step catch { set param "$interact_out(2,string)" } error # increment buffer line pointer incr _el_buf($_el_buf(stack),ptr) # read line from buffer set line [ _el_buffer_read $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ] set line_meta [ _el_buffer_read $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) 1] #puts "==BUF====>$_el_buf($_el_buf(stack),ptr)|$line|$line_meta\n" switch -regexp -- $line { {^\*INT} { # skip interact lines cputs "$line" $_el_info_color protected_send "$_el_eols" } {^\*FORK} { # Allow interact to return, since it hangs onto old session if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color _el_script_exec "\|$line" $_el_buf(stack) # allow interact to return, for new/changed session return } } ^\! { # Send prompt after native expect lines if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color _el_script_exec "\|$line" $_el_buf(stack) # kick the prompt protected_send "$_el_eols" } } ^\> { # send line out and clump any following lines with < or +$ # clear clump list set cli_list "" # add lines to clump while {$line!=-1} { lappend cli_list $line incr _el_buf($_el_buf(stack),ptr) # read line from buffer set line [ _el_buffer_read $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ] #puts "===L==>$line" # is line part of clump: expect, dynvar, not-expect if {[regexp {^\<|^\+\$|^\-\<} $line] == 0} { #No more clump, roll back pointer incr _el_buf($_el_buf(stack),ptr) -1 set line -1 } } # send clump to _el_script_exec #send_user "=====>$cli_list||$_el_buf(stack)" foreach item $cli_list { if { $item != "" } { if { $param == "k" } { cputs "Skipping:$item" $_el_info_color protected_send "$_el_eols" } else { # execute next step cputs "$item" $_el_info_color _el_script_exec "\|$item" $_el_buf(stack) } } } # end clump send } ^\~[^=<] { # include a file if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color # kick the prompt protected_send "$_el_eols" _el_script_exec "\|$line" } } {^\?.+\?} { # if with code block #{^\?.+\?.+\[} if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color # kick the prompt protected_send "$_el_eols" # does this line have a jump-to-label? # run if statement with $_el_buf(stack) context set retcode [_el_script_exec "\|$line" $_el_buf(stack)] #puts "=====>$retcode|$line|$line_meta" # retcode 1 = result true, 0 = result false # jump past code block if {$retcode == 1 } { # else action if {[regexp {^\?.+\?.+::[ ]*\[} $line ]} { _el_buffer_goto [expr $line_meta ] $_el_buf(stack) } } else { # action if {[regexp {^\?.+\?[^:]*\[} $line ]} { _el_buffer_goto [expr $line_meta ] $_el_buf(stack) } } # kick the prompt protected_send "$_el_eols" } } ^\\\[ { # begining while block if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color # kick the prompt protected_send "$_el_eols" set retcode [ _el_script_exec "\|$line" ] # retcode 1 = result true, 0 = result false if {$retcode == 1 } { # continue the loop #set _el_buf($_el_buf(stack),ptr) [expr $line_meta - 1] } else { # make the jump passed while loop _el_buffer_goto [expr $line_meta ] $_el_buf(stack) } # kick the prompt protected_send "$_el_eols" } } ^\\\] { # end while block if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color # make the jump _el_buffer_goto [expr $line_meta - 1 ] $_el_buf(stack) # kick the prompt protected_send "$_el_eols" } } "-1" { cputs "End of File" $_el_warn_color } default { if { $param == "k" } { cputs "Skipping:$line" $_el_info_color protected_send "$_el_eols" } else { cputs "$line" $_el_info_color #puts "---->$::spawn_id" set _el_result [ _el_script_exec "\|$line" $_el_buf(stack)] if {$_el_result == 1 } { # step failed? kick the prompt protected_send "$_el_eols" } } } } } -re {^(\x1b|`)([-]?[0-9])} { #DEBUGGER .-1to9 Show next or last 1-9 lines # .1to9 or .-1to9 #send_user "=====>[scan $interact_out(0,string) %c]|$interact_out(0,string)" #catch { set param "$interact_out(1,string)" } error catch { set param "$interact_out(2,string)" } error _el_buffer_show $param $_el_buf(stack) protected_send "$_el_eols" } -re {^\x1bv|`v} { #DEBUGGER .v Show Vars show_vars protected_send "$_el_eols" } -re {^(\x1b|`)(e)} { #DEBUGGER .e Show expect-lite Environment show_environment protected_send "$_el_eols" } -re {^(\x1bh|`h)} { #DEBUGGER .h Show help interact_help protected_send "$_el_eols" } -echo -re {^(>[a-zA-Z0-9/$.]|\?[iI][fF]|\$[a-zA-Z0-9_]+=|~[a-zA-Z0-9]|; [^\r\n]|\*[A-Z]|\+\$|=\$|%[A-Z]|\[ )(.+)\r|(^@[0-9]+\r)|(\]\r)} { #### Support for EL commands in Interact #### Permits pasting of multiple commands into Interact session #### test for expect version - 5.26 does not paste # create list of multiple pasted commands set cli_list [split $interact_out(0,string) "\r"] # OS identification - .dll or "" = Cygwin, .so=Linux, .dylib=MacOS X set os_id [info sharedlibextension] if { $os_id == ".dll" || $os_id == "" } { # Special expect to pick up Cygwin Pasted lines, which come one at a time while 1 { expect_user { -re {(.+)\r} { # strip newlines and add to cli_list regsub {\n|\r|\r\n} $expect_out(1,string) "" cli_item lappend cli_list $cli_item } -timeout 1 timeout { break } -re \003 {puts "\nAck!\n"; exit 1} } } # end while } # remove extraneous end of lines (paste into putty from windows) regsub {\n|\r|\r\n} $cli_list "" cli_list #end if os_id # clear line of pasted text send_user " \r" # signal to paste lines outside of interact loop set _el(ide_paste_lines) 1 return } } } \ error] } { puts stderr "CONNECT ERROR: lost connection to $remote_host \n $error \nExiting..." # Fail script? exit 1 } if {$_el(ide_paste_lines)} { if {$DEBUG} { send_user "\nDEBUG: Evaluating:\n" foreach d_item $cli_list { send_user "\t$d_item\n" } } #send_user "\n=====>$cli_list\n" # special case of one line: if jump to label set _buf_ptr [lsearch -regexp $cli_list {\?.+\?.*%} ] if { $_buf_ptr == 0} { # get line from paste input, and execute if-jump-to-label in main script set _line [lindex $cli_list $_buf_ptr] _el_script_exec "\|$_line" $_el_buf(stack) } else { # multiple lines pasted, treat as small script # pasted lines operate in own paste buffer, # and can not access lines (via jumping) in main script # assign meta-data to list set i 0 # clear the block stack _el_buffer_block_clear set paste_buf_ptr [ _el_buffer "" $cli_list ] protected_send "$_el_eols" # call el script exec set rtncode [ _el_script_exec "" $paste_buf_ptr ] if { $paste_buf_ptr == $_el_buf(stack) } { # clear list in buffer stack and pop stack number if not popped _el_buffer_stack_clear $expectlite::_el_buf(stack) } }; #endif }; #endif paste lines protected_send "$_el_eols" }; #end while # restore script session session_id_manager [ pop_session_id ] set _el(success) 1 protected_send "$_el_eols" # restore NOFAIL incr NOFAIL -1 } # # Prompts are always a problem, this should _not_ require customization with the # addition of User Defined Prompts '*/some_regex/' as of version 3.1.5 # These prompt regexs are setup to take just about any non-color prompt: >#%$ # # proc wait_for_prompt { } { global timeout expect_out upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG upvar expectlite::_el _el #Accept '>' '#' '%' or '$' prompt if { $timeout == 0 } { # delay in ms after 50 } set TIMEOUT_RETURN 0 # User Defined prompt is $_el(prompt) if {[catch { expect { -re "$_el(prompt)" { } -re ".*> $" { } -re ".*# $" { } -re ".*% $" { } -re {.*\$ $} { } timeout { if {$WARN} { cputs "Warning:Prompt Timed Out!" $_el_warn_color} set TIMEOUT_RETURN 1 # is user defined prompt being used? if { $_el(default_prompt) != $_el(prompt)} { if {$DEBUG} { # gobble as much return text as possible expect -notransfer -re ".*\n+" { } # print out debug info to help user cputs "DEBUG: User Defined Prompt:<<$_el(prompt)>>" $_el_debug_color cputs " Not Found in<<$expect_out(buffer)>>" $_el_debug_color } } } } } \ error ] } { puts "\nERROR: $error: Bad User Defined Prompt: $_el(prompt)" # Quit expect-lite exit 1 } if {$TIMEOUT_RETURN} { return 1 } else { return 0 } } # # Print Usage # # proc usage {} { upvar expectlite::version version puts " " puts "usage: expect-lite -c \[ -r \] \[-d \] \\ " puts " \[const1=value1\] \[*DIRECTIVE\]" puts " eg. ./expect-lite -c pm_alt.elt -r host8 -d /home/sw myvar=myvalue *NOFAIL" puts " " puts " additional login options: -u -p " puts " eg. ./expect-lite -c pm_alternation.elt -r host-008 -u superuser -p mysecret" puts " " puts " additional logging options: -V|-v|-vv|-vvv" puts " -V prints \'expected\' lines (i.e lines beginning with < & << )" puts " -v prints info and warnings (i.e. conditionals,dynamic vars)" puts " -vv prints warnings and debug (i.e. expect match info) " puts " -vvv prints info, warnings and debug " puts " eg. ./expect-lite -vv -r host8 -c pm_alt.elt " puts " " puts "If set, environment variables starting with EL_ will be used " puts " See man page or documentation for full list of env vars" puts " " puts " Version $version by Craig Miller" exit 0 } # # Initializes Library function of expect-lite # Pass in values for Constants and Directives (cli_str) # Set library_mode, and connect to bash # proc _el_init_library { {cli_str ""} } { # script will core dump if libexpect is wrong version #puts "tclsh version:[info patchlevel]|[info tclversion]" if { [ catch {[package present Expect] } error ]} { #puts $error if { [info tclversion ] != "8.5" } { # check tclsh version before loading libexpect puts "ERROR:tclsh version mismatch with libexpect, expected version 8.5, using tclversion:[info tclversion ]" exit 1 } package require Expect } # test expect extensions if {[ catch { send_user "libexpect loaded\n"} error ]} { puts "ERROR: libexpect not loaded \n$error\n" exit 1 } # load el globals _el_init_globals # set el library mode set ::EL_LIBRARY 1 # ignore *INTERACT directive set expectlite::NOINTERACT 10 # Read arguments to el_lib and call el_read_args # count words on cli_str set argc [llength [split $cli_str " "]] _el_read_args $argc $cli_str # spawn to bash for now #_el_connect_localhost "" } # # Imports expect-lite constants into expect-lite # Pass in values for Constants and Directives (cli_str) # Can be called multiple times, values are additive # proc _el_import_const { {cli_str ""} } { # Read arguments to el_lib and call el_read_args # count words on cli_str set argc [llength [split $cli_str " "]] _el_read_args $argc $cli_str } # # Takes full command path+file, and returns just the file name minus path # # proc parse_cmd_file_nopath { cmd_file } { # Is there a path component? if {[regexp {/} $cmd_file] == 1 } { set temp_list [split $cmd_file '/'] set len [expr [llength $temp_list] - 1 ] return [lindex $temp_list $len] } else { return $cmd_file } } # # Assign cli arguments to the variable names # Requires that $remote_host and $cmd_file are passed in via cli or # that shell enviroment vars be set prior to running # EL_REMOTE_HOST # EL_CMD_FILE # EL_USER_DIR # EL_CONNECT_METHOD # EL_CONNECT_USER # EL_CONNECT_PASS # EL_LOG_EXT # EL_INFINITE_LOOP # EL_DELAY_WAIT_FOR_HOST # EL_SHELL # proc _el_read_args { argc argv } { global env upvar expectlite::remote_host remote_host upvar expectlite::cmd_file cmd_file upvar expectlite::user_dir user_dir upvar expectlite::connect_method connect_method upvar expectlite::user user upvar expectlite::pass pass upvar expectlite::delay_wait_for_host delay_wait_for_host upvar expectlite::_el_infinite_loop _el_infinite_loop upvar expectlite::remote_shell remote_shell upvar expectlite::cli_namespace cli_namespace upvar expectlite::timeout_multiplier timeout_multiplier upvar expectlite::arg0 arg0 upvar expectlite::INFO INFO upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG upvar expectlite::LOG LOG upvar expectlite::EXP_INFO EXP_INFO upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::SHOW_HELP SHOW_HELP upvar expectlite::el_log_ext el_log_ext upvar expectlite::DVARPROMPT DVARPROMPT # default timeout_multiplier multiplier to 1 set cli_namespace($timeout_multiplier) 1 # command file (aka script name) counter set cmd_file_counter 0 # If needed read parameters from Env Vars catch { set remote_host $env(EL_REMOTE_HOST)} catch { set DVARPROMPT $env(EL_DYN_VAR_PROMPT)} if { $remote_host == "" } { set remote_host "none" } if { $cmd_file=="" } { catch { set cmd_file $env(EL_CMD_FILE)} } if { $user_dir=="" } { catch { set user_dir $env(EL_USER_DIR)} } if { [info exist env(EL_LOG_EXT) ]} { catch { set el_log_ext $env(EL_LOG_EXT)} } # check for empty el_log_ext string if { $el_log_ext == "" } { cputs "expect-lte: ERROR: Environment var EL_LOG_EXT is blank, which could overwrite script file.\nSetting extension to \".log\"" $_el_err_color set el_log_ext ".log" } # preset local var set infinite_loop $_el_infinite_loop if { [info exist env(EL_INFINITE_LOOP) ]} { catch { set infinite_loop $env(EL_INFINITE_LOOP)} } # check for number el_infinite_loop string if { [string is integer -strict $infinite_loop] } { set _el_infinite_loop $infinite_loop } else { cputs "expect-lte: ERROR: Environment var EL_INFINITE_LOOP is blank or not a number.\nSetting INFINITE_LOOP to: $_el_infinite_loop" $_el_err_color } if { $user=="" } { catch { set user $env(EL_CONNECT_USER)} } if { $pass=="" } { catch { set pass $env(EL_CONNECT_PASS)} } if { [info exists env(EL_CONNECT_METHOD)] } { catch { set connect_method $env(EL_CONNECT_METHOD)} } if { [regexp {none|telnet|ssh|ssh_key} $connect_method] == 0 } { set connect_method "none" } if { [info exists env(EL_DELAY_WAIT_FOR_HOST)] } { catch { set delay_wait_for_host $env(EL_DELAY_WAIT_FOR_HOST)} } if { $delay_wait_for_host == "" } { set delay_wait_for_host "100" } if { [info exists env(EL_SHELL)] } { catch { set remote_shell $env(EL_SHELL)} } # ensure arg list is separated by spaces - removed in 4.2.0 # set argvstr [ join $argv ] # set argv [split $argvstr ] # set argc [ llength $argv ] if { $argc >= 1 || $cmd_file!="" } { # Walk thru additional args (should be cli constants) for { set x 0 } { $x < $argc} { incr x } { set optarg [ lindex $argv $x ] catch {set optargval [ lindex $argv [expr $x + 1]]} if { $optargval == "" } { # no optargval, set to a sane value set optargval "--" } #puts "=====>$x|$optarg|$optargval|" # Check that last parameter is command file name # script name cannot have '=', which would be interpretted as a constant if { [regexp {^[-*]|[=]} $optarg ] == 0 && [regexp {^[-*]|[=]} $optargval] == 1 } { if { [regexp "$el_log_ext$" $optarg] == 0 } { #puts ">>>$optarg>>>$optargval" set cmd_file $optarg set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file] incr cmd_file_counter } } # look for help & debug options which overide script options # added -r and -c for remote_host & cmd_file respectively if { [catch { switch -glob -- $optarg { -h - --help { set SHOW_HELP 1 } -v {set WARN 10; set INFO 10} -vv - --verbose {set WARN 10; set DEBUG 10} -vvv {set INFO 10; set WARN 10; set DEBUG 10} -V - --verify {set EXP_INFO 10; set INFO 10} -r { set remote_host $optargval; incr x } -c { set cmd_file $optargval; set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file] ; incr x } -d { set user_dir $optargval; incr x } -u { set user $optargval; incr x } -p { set pass $optargval; incr x } } } \ error ] } { puts "Warning: Bad input option: $error" } #general vars if [ regexp {.+=.*} $optarg ] { # detect and parse args in format "var=value" set user_var [string range $optarg 0 [expr [string first "=" $optarg] -1 ]] set user_value [string range $optarg [expr [string first "=" $optarg] +1 ] [string length $optarg]] #puts "->$user_var $user_value" # populate required cli parameters and cli_constants switch -glob -- $user_var { remote_host - r { set remote_host $user_value } cmd_file - c { set cmd_file $user_value # set script constant arg0 with script name set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file] } user_dir - d {set user_dir $user_value } user_name - u {set user $user_value } user_password - p {set pass $user_value } default { set cli_namespace($user_var) $user_value puts "Const: $user_var = $cli_namespace($user_var)" } } } } ; # for loop # walk though CLI options again and check for *DIRECTIVES for { set x 0 } { $x < $argc} { incr x } { set optarg [ lindex $argv $x ] catch {set optargval [ lindex $argv [expr $x + 1]]} if { $optargval == "" } { # no optargval, set to a sane value set optargval "--" } #puts "=====>$x|$optarg|$optargval|" #cli-based directives (in form *DIRECTIVE) if [ regexp {\*[A-Z_]+} $optarg] { # check if optargval is just a word set chk_word "" #regsub {[a-zA-Z./]+} $optargval {} chk_word regsub {(^[-*]|[^*=]+)} $optargval {} chk_word #puts "===>got $optarg|$optargval|$el_log_ext|$chk_word|" if { [string length $chk_word] != 0 } { # just *LOG on the cli _el_global_directive $optarg } elseif { [regexp {^[-*]|[=]} $optargval ] } { # next arg is -,*DIR, or var=value _el_global_directive $optarg } elseif { [string match "*$el_log_ext" $optargval ] } { # next arg is *LOG _el_global_directive "$optarg $optargval" # increment loop to skip optargval incr x } elseif {[string match "*$el_log_ext" $optargval ] == 0} { # check again to see that second item doesn't end in .log # just *LOG on the cli _el_global_directive $optarg } ; # end if } } ; # for loop # assign over riding directives if { $LOG } { set LOG 10 } if { $LOG < 0 } { set LOG -10 } if { $INFO > 1 } { set INFO 10 } if { $WARN > 1 } { set WARN 10 } if { $DEBUG } { set DEBUG 10 } if { $EXP_INFO } { set EXP_INFO 10 } #puts "->$remote_host|$cmd_file|$user_dir" # check that require paremeters are present if { $remote_host=="" } { cputs "Error: Missing remote_host" $_el_err_color usage } if { [info exists ::EL_LIBRARY] != 1 && $remote_host=="none" || $remote_host=="NONE" } { if {$WARN} { cputs "Warning: Remote Host=none, using Localhost" $_el_warn_color } # don't use remote login method but use localhost set connect_method "none" } if { $cmd_file=="" && [info exists ::EL_LIBRARY] != 1} { cputs "Error: Missing cmd_file" $_el_err_color usage } # check that only 1 script name was on the CLI #puts "========>$cmd_file_counter|$LOG|$cmd_file" if { $cmd_file_counter > 1 && $LOG != 0} { puts stderr "Error: Can't determine cmd_file name with *LOG, please use log file with extension:$el_log_ext" exit 1 } } # Assign any Environment Variables starting with 'EL_' to Constants # only show in Debug and not Library mode if { $DEBUG && [info exists ::EL_LIBRARY] != 1} { cputs "expect-lite version $expectlite::version" $_el_debug_color cputs "Env Vars -> Constants:" $_el_debug_color } foreach key [array names env] { if {[regexp {^EL_} $key] == 1 } { if { $DEBUG && [info exists ::EL_LIBRARY] != 1} { cputs "$key=$env($key)" $_el_debug_color } set cli_namespace($key) $env($key) } } # validate ENV Vars switch -glob -- $cli_namespace(EL_CONNECT_METHOD) { none - ssh - ssh_key - telnet { # do nothing } default { cputs "ERROR: EL_CONNECT_METHOD set incorrect! Set to: $cli_namespace(EL_CONNECT_METHOD)" $_el_err_color cputs "Please set to one of: none, telnet, ssh, ssh_key" $_el_err_color cputs "export EL_CONNECT_METHOD=telnet" $_el_err_color exit 1 } } if {[info exists ::EL_LIBRARY] != 1} { # show help if command file (script) is not given on command line if { $argc < 1 && $cmd_file=="" } { usage } } } # # Takes full command path+file, and returns just the path to command file minus the filename # This is used in including files # proc parse_cmd_file_path { cmd_file } { # Is there a path component? if {[regexp {/} $cmd_file] == 1 } { set temp_list [split $cmd_file '/'] set len [expr [llength $temp_list] - 1 ] regsub [lindex $temp_list $len] $cmd_file "" temp_path return $temp_path } else { return "" } } # # Reads in main command file, and if show_help is true, shows help and exits # # proc read_cmd_file { } { upvar expectlite::cmd_file cmd_file upvar expectlite::INFO INFO upvar expectlite::WARN WARN upvar expectlite::_el_info_color _el_info_color upvar expectlite::SHOW_HELP SHOW_HELP upvar expectlite::arg0 arg0 upvar expectlite::_el_buf _el_buf upvar expectlite::_include _include upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::DEBUG DEBUG upvar expectlite::_el _el # read this file as el script, reference by buf_stack pointer set cmd_list_ptr [expectlite::_el_buffer $cmd_file] # preserve cmd_file for later use set _el(cmd_file) $cmd_file # validate include files set missing_include 0 set inc_files [_el_buffer_get_obj $cmd_list_ptr ~] foreach line $inc_files { set _include_file [_el_strip_char $line $_include] # get only the first word as include file set _include_file [lindex [split $_include_file " " ] 0] # is include file a variable or fuzzy expect (could be ~=$var), skip validation if { [ regexp {^\$|^\<|^=\$?[a-zA-Z0-9]|^=} $_include_file ] == 0 } { # normalize file name to read to allow tilde expansion e.g. ~fred/file.inc if { [catch { file normalize $_include_file } error ] == 0 } { set _include_file [file normalize $_include_file ] } else { if {$WARN} { cputs "\nWarning: $error\n" $_el_warn_color } } # absolute path to include file? set _slash "/" if { [string index $_include_file 0] == $_slash} { set include_path_file "$_include_file" } else { set include_path_file "[parse_cmd_file_path $cmd_file]$_include_file" } # validate include file if { $DEBUG } { cputs "Checking include file exists: $include_path_file" $_el_debug_color } if {[file exists $include_path_file] == 0} { cputs "$include_path_file not found!" $_el_err_color incr missing_include } } }; #foreach # if needed show help and exit if { $SHOW_HELP } { cputs "Help for: $cmd_file" $_el_info_color _el_buffer_show_help $cmd_list_ptr cputs "Displaying assigned variables, which can be overridden with \na Constant on command line e.g var=value" $_el_info_color set var_list [_el_buffer_get_obj $cmd_list_ptr] set var_list [ lsort -unique $var_list ] foreach line $var_list { # remove $ from help lines regsub {\$} $line {} line puts "\t$line" } usage exit 1 } if { $missing_include } { cputs "\nMissing required include files, exiting..." $_el_err_color # exit with abend code exit 2 } # return the pointer to the buffer return $cmd_list_ptr } # # Login Method which uses user and password via Telnet to log into hosts # If this is not your access method use one of the other login methods # proc connect_telnet_host {remote_host {optional_suppress_stdout "no"}} { global spawn_id upvar expectlite::DEBUG DEBUG upvar expectlite::_el_timeout _el_timeout upvar expectlite::_el_telnet _el_telnet upvar expectlite::user user upvar expectlite::pass pass #This spawns the telnet program - auto generates spawn_id var set timeout 5 if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} { # turn off stdout - suppress login banners - show with -vv log_user 0 } if { [catch { spawn $_el_telnet $remote_host } error] } { puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error" # Fail script? exit 1 } #The script expects login expect "ogin:" #The script sends the user variable if { [catch { send -- "$user\r" } error] } { puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error\n $errorInfo\nExiting..." # Fail script? exit 1 } #The script expects Password expect "assword:" #The script sends the password variable # do not log password set log_user 0 send -- "$pass\r" set log_user 1 #wait_for_prompt set timeout $_el_timeout # turn on stdout log_user 1 } # # Subroutine used by ssh user/password method # If this is not your access method use one of the other login methods # proc zlogin { {pass ""} {login_attempts 2} } { upvar expectlite::remote_host remote_host upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_eols _el_eols upvar expectlite::WARN WARN set timeout 2 set MAXLOGINATTEMPT 10 #set login_attempts 0 while { $login_attempts < $MAXLOGINATTEMPT} { #puts "loop: $login_attempts" expect { -re "assword:" { # do not log password set log_user 0 send -- "$pass$_el_eols" set log_user 1 #puts "send pass" } -re "Are you sure you want to continue connecting" { send -- "yes$_el_eols" #zlogin $pass $login_attempts } -re "Warning: Permanently added .* to the list of known hosts" { if {$WARN} { cputs "Expect-lite: Warning: ssh added host key to known hosts" $_el_warn_color } } -re "Last login" { return } -re {.*[>#%$] $} { return } -re {.+\n} { #expect connected } } incr login_attempts #puts "here" } if { $login_attempts >= $MAXLOGINATTEMPT} { puts stderr "\nCONNECT ERROR:Unable to login to $remote_host \n " exit 1 } } # # Login Method which uses user and password via ssh to log into hosts # If this is not your access method use one of the other login methods # proc connect_ssh_host {remote_host {optional_suppress_stdout "no"}} { global spawn_id env upvar expectlite::user user upvar expectlite::pass pass upvar expectlite::_el_timeout _el_timeout upvar expectlite::DEBUG DEBUG upvar expectlite::connect_ssh_accept_host_key connect_ssh_accept_host_key # work around for older versions of expect #This spawns the ssh program - auto generates spawn_id var #spawn ssh -l $user $remote_host set timeout 15 if { $user == "" } { # user username from environment set user $env(USER) } # suppress stdout during login if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} { # turn off stdout - suppress login banners - show with -vv log_user 0 } # create ssh command line set connect_cmd [concat ssh $connect_ssh_accept_host_key -l $user $remote_host] #This spawns the ssh program - auto generates spawn_id var if { [catch "spawn $connect_cmd" error] } { puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error" # Fail script? exit 1 } # debug help #exp_internal 1 set login_attempt 0 #better way of logging in (and catch any errors) if { [ catch {zlogin $pass $login_attempt} error] } { puts stderr "CONNECTION ERROR to $remote_host \n $error" exit 1 } # turn off the debugging #exp_internal 0 set timeout $_el_timeout # turn on stdout log_user 1 } # # Login Method which assumes ssh keys are configured for login hosts # If this is not your access method use one of the other login methods # proc connect_ssh_key_host {remote_host {optional_suppress_stdout "no"}} { global spawn_id timeout upvar expectlite::user user upvar expectlite::pass pass upvar expectlite::DEBUG DEBUG upvar expectlite::delay_wait_for_host delay_wait_for_host upvar expectlite::_el_eols _el_eols upvar expectlite::connect_ssh_accept_host_key connect_ssh_accept_host_key upvar expectlite::_el_timeout _el_timeout # work around for older versions of expect # Enable use of an alternet user for ssh_key method # if $user is not blank, then use the alternet user set timeout 30 if { $user != "" } { set login_user "$user@" } else { set login_user "" } # suppress stdout during login if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} { # turn off stdout - suppress login banners - show with -vv log_user 0 } #This spawns the ssh program - auto generates spawn_id var set connect_cmd [concat ssh $connect_ssh_accept_host_key $login_user$remote_host] if { [catch "spawn $connect_cmd" error] } { puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error" # Fail script? exit 1 } # TODO:Auto update ~/.ssh/known_hosts if needed #better way of logging in (and catch any errors) if { [ catch {zlogin} error] } { puts stderr "CONNECTION ERROR to $remote_host \n $error" exit 1 } # Test the connection by sending a return if { [catch { send -- "$_el_eols" } error] } { puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error" # Fail script? exit 1 } # allow time for remote banner (if present) to echo #after [expr $delay_wait_for_host * 2] # answer quetion if given, else take any response as "connected" set timeout 5 expect { -re "Are you sure you want to continue connecting" { send -- "yes$_el_eols" } -re {.+} { #puts "expect-lite: Connected" } timeout { } } # debug help #exp_internal 1 # turn off the debugging #exp_internal 0 set timeout $_el_timeout # turn on stdout log_user 1 } # # Login Method connects to localhost (no telnet or ssh) # If this is not your access method use one of the other login methods # proc _el_connect_localhost {remote_host} { # this proc just spawns a connection to a shell # all other functions are handled by remote_host_init global spawn_id timeout upvar expectlite::remote_shell remote_shell upvar expectlite::_el_eols _el_eols # OS identification - .dll or "" = Cygwin, .so=Linux, .dylib=MacOS X set os_id [info sharedlibextension] if { $os_id == ".dll" || $os_id == "" } { set timeout 30 } # protect against empty remote_shell if { $remote_shell == "" } { set remote_shell "bash" } # spawn a local shell for localhost if { [catch { spawn $remote_shell } error] } { puts stderr "CONNECT ERROR: Unable to connect to localhost \n $error" # Fail script? exit 1 } send -- " $_el_eols" set timeout 10 } # # Reads configuration directives, prior to command file execution # Sets global variables # This function will eventually replace all user defined globals at top of script # proc read_set_config_directives { buf_stack } { upvar expectlite::remote_shell remote_shell upvar expectlite::_el_buf _el_buf # search for shell configuration directive (**SHELL=...) #set _search "^\\\*\*SHELL=.*" set _search "\{\\\*\*SHELL=.*" # search buffer _el_buf($buf_stack) with $_search #set _buf_ptr [lsearch -regexp -index 0 $_el_buf($buf_stack) "$_search"] set _buf_ptr [lsearch -regexp $_el_buf($buf_stack) "$_search"] set _line [_el_buffer_read $_buf_ptr $buf_stack] #puts "shell_line-------->$_line|$_buf_ptr" if { $_buf_ptr != -1 } { set _line_list [split $_line "="] if { [llength $_line_list ] == 2 } { set remote_shell [lindex $_line_list 1] } puts "expect-lite directive: Shell is: $remote_shell" } } # # Wraps expect send command in catch, reports error if connection is lost # Error condition terminates script # proc protected_send { str } { upvar expectlite::remote_host remote_host if { [catch { send -- "$str" } error] } { puts stderr "CONNECT ERROR: Unable to connect to remote_host: $remote_host \n $error" # Fail script? exit 1 } } # # After logged into remote host, does house keeping activities before starting expect-lite script # starts shell on remote host, sets sane prompt, and cd's to user directory (aka user_dir) if needed # proc remote_host_init { user_dir } { global spawn_id timeout expect_out upvar expectlite::remote_host remote_host upvar expectlite::remote_shell remote_shell upvar expectlite::DEBUG DEBUG upvar expectlite::_el_timeout _el_timeout upvar expectlite::connect_method connect_method upvar expectlite::delay_wait_for_host delay_wait_for_host upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_eols _el_eols set timeout 5 #set an initial sane value set detected_prompt "$ " # suppress stdout during login for *FORK if { $DEBUG > 0 } { # turn off stdout - suppress login banners - show with -vv log_user 0 } # ensure we are using user's desired shell, and check connection if {$connect_method != "none" } { # handle real remote host invocation of shell protected_send "$remote_shell$_el_eols" # wait for echo to appear when starting a shell if { $remote_shell != "" } { expect { -re ".+\[%>#$\] $remote_shell.+" { if {$DEBUG} { cputs "DEBUG: Starting Shell: $remote_shell\n" $_el_debug_color} } timeout { if {$DEBUG} { cputs "DEBUG: Unable to detect Shell Start\n" $_el_debug_color} } } } } else { #connect_method is none - set to speed up "none" operation set delay_wait_for_host [expr $delay_wait_for_host / 4 ] } # attempt to detect shell by prompt protected_send "$_el_eols" expect -re {([%>#$]) $} { if {$DEBUG} { cputs "<<$expect_out(0,string)>>" $_el_debug_color} #puts "<<$expect_out(buffer)>>" set detected_prompt $expect_out(0,string) } if {$connect_method == "none" } { # kick things to keep it moving protected_send "$_el_eols" } # set sane prompt switch -glob -- $remote_shell { csh - tcsh { set _prompt "%c02 %# %L" protected_send "set prompt = \"$_prompt\"$_el_eols" expect -re {.+prompt.+} { } } sh - ksh - bash { set _prompt "\"\[\\u@\\h:\\w\]\\$ \"" #set _prompt "\'\\$ \'" protected_send "PS1=$_prompt$_el_eols" expect -re {.+PS1.+} { } } default { switch -glob -- $detected_prompt { "# " - "$ " { set _prompt "\$ " protected_send "export PS1=\'$_prompt\'$_el_eols" if {$DEBUG} { cputs "DEBUG: Setting sh prompt. \n" $_el_debug_color} } "% " - "> " { set _prompt "\$ " protected_send "set prompt = \"$_prompt\"$_el_eols" if {$DEBUG} { cputs "DEBUG: Setting csh prompt. \n" $_el_debug_color} } } } } # clear expect_out(buffer) #expect -re {.+} {} # turn on stdout log_user 1 #only change directory if user_dir was passed as an arg, otherwise, user will set it in expect-lite script if { $user_dir != "" } { protected_send "cd $user_dir$_el_eols" wait_for_prompt } set timeout $_el_timeout } # # initialize session and remote host # # proc session_init { cmd_file_ptr } { upvar expectlite::user_dir user_dir upvar expectlite::_el_fork _el_fork upvar expectlite::_el_eols _el_eols # is main script name equal to command file (script) name # or Is this an include file, then don't do remote_host_init read_set_config_directives $cmd_file_ptr # init prompt for first (default) session remote_host_init $user_dir # kick the prompt protected_send "$_el_eols" # set default fork session if it doesn't already exist if { [info exists _el_fork(default,session)] != 1 } { if { [catch { set _el_fork(default,session) $::spawn_id } error] } { puts stderr "BUG: Expect-lite: Bug in _el_script_exec init code while setting default FORK session \n $error" # Fail script? exit 1 } } } # # Control spawn_id sessions on host # # proc session_id_manager { fork_id } { global spawn_id timeout upvar expectlite::_el _el upvar expectlite::_el_fork _el_fork upvar expectlite::_el_fork_id_list _el_fork_id_list upvar expectlite::INFO INFO upvar expectlite::connect_method connect_method upvar expectlite::remote_host remote_host upvar expectlite::DEBUG DEBUG upvar expectlite::user_dir user_dir upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_eols _el_eols if { $fork_id == "default" } { # set fork session back to default if count > 0 if { $_el(fork_count) > 0 } { set spawn_id $_el_fork(default,session) } } elseif { $fork_id != "" } { # request for new fork session if {[info exists _el_fork($fork_id,session) ]} { # connect to existing session set spawn_id $_el_fork($fork_id,session) } else { # save current timeout set current_timeout $timeout # start new session on remote_host # Use selected (at top of this file) connect_method switch $connect_method { telnet {connect_telnet_host $remote_host "suppress_stdout" } ssh {connect_ssh_host $remote_host "suppress_stdout" } ssh_key {connect_ssh_key_host $remote_host "suppress_stdout"} none {_el_connect_localhost $remote_host } } # set a sane prompt for additional sessions remote_host_init $user_dir # restore current timeout set timeout $current_timeout set _el_fork($fork_id,session) $spawn_id incr _el(fork_count) # update list of fork_id's lappend _el_fork_id_list $fork_id # set default eols for this session set _el_fork($fork_id,eols) $_el_eols } # end if } elseif {$fork_id == "" } { # Show current session name if { [info exists _el(fork_current)] } { set fork_id $_el(fork_current) } else { set fork_id "default" } } # clear and regenerate fork id list and count set _el_fork_id_list { } set _el(fork_count) 0 foreach keyitem [array names _el_fork] { #filter out eols from session printout if { [string match "*,session" $keyitem] } { # retrieve session name, drop ',session' from keyitem set session_name [lindex [split $keyitem ,] 0] lappend _el_fork_id_list $session_name incr _el(fork_count) #puts "=====>$keyitem|$session_name|$_el_fork_id_list|$_el(fork_count)" } } if {$INFO && !$DEBUG} { cputs "\n\nINFO: FORK session is: $fork_id, Active sessions are: $_el_fork_id_list\n" $_el_info_color } elseif { $DEBUG } { cputs "\n\nDEBUG: FORK session is: $fork_id, Spawn_id=$spawn_id, fork_count:$_el(fork_count), active sessions:$_el_fork_id_list\n" $_el_debug_color } set _el(fork_current) $fork_id return $fork_id } # # el_lib: import session names and spawn_ids # Enables external app to spawn sessions, and feed list to EL # proc _el_import_session_ids { session_list } { global spawn_id upvar expectlite::_el _el upvar expectlite::_el_fork _el_fork upvar expectlite::_el_fork_id_list _el_fork_id_list upvar expectlite::INFO INFO upvar expectlite::DEBUG DEBUG upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_eols _el_eols puts "SL>$session_list|[llength $session_list]" if { [ catch { array set import_fork $session_list} error ]} { cputs "ERROR: Invalid array:$session_list:\n$error\n" $_el_err_color } # set current fork_id to current spawn_id foreach keyitem [array names import_fork] { #filter out eols from keyitems puts "SL>$keyitem" # set current fork_id to current spawn_id puts "SL2>$keyitem" if { [info exists spawn_id ] && $import_fork($keyitem,session) == $spawn_id } { set _el(fork_current) $keyitem set _el_fork(fork_current,eols) $_el_eols } # set default eol context set _el_fork($keyitem,eols) $_el_eols } # set spawn_id to default, if not currently set if { [info exists spawn_id ] != 1 && [ info exists import_fork(default)] } { set spawn_id $import_fork(default) } else { cputs "ERROR: Import Sessions: no 'default' session found\n Sessions imported: [array names import_fork]" $_el_err_color exit 1 } # convert imported session array to el_fork array foreach keyitem [array names import_fork] { set _el_fork($keyitem,session) $import_fork($keyitem) } # show array if { $DEBUG } { cputs "Printing session ids:" $_el_debug_color foreach keyitem [array names _el_fork] { #filter out eols from session printout if { [string match "*session*" $keyitem] == 1 } { set session_name [lindex [split $keyitem ,] 0] cputs " $session_name=$_el_fork($keyitem)" $_el_debug_color } } }; #endif DEBUG } # # push spawn_id sessions on fork_id stack # used by interact # proc push_session_id { fork_id } { global spawn_id upvar expectlite::_el _el upvar expectlite::_el_fork _el_fork upvar expectlite::_el_fork_stack _el_fork_stack upvar expectlite::INFO INFO upvar expectlite::DEBUG DEBUG # remove any \n or \r's regsub -all {[ \n\r]+} $fork_id "" fork_id if { [string length $fork_id ] > 0 } { # push new session_id on stack lappend _el_fork_stack $_el(fork_current) } set len [llength $_el_fork_stack] } # # pop spawn_id sessions from fork_id stack # used by interact, to set proper *FORK session when continuing the expect-lite script # proc pop_session_id { } { global spawn_id upvar expectlite::_el _el upvar expectlite::_el_fork _el_fork upvar expectlite::_el_fork_stack _el_fork_stack upvar expectlite::INFO INFO upvar expectlite::DEBUG DEBUG if {[info exists _el_fork_stack ]} { set len [llength $_el_fork_stack] if { $len > 0 } { # get last value on stack set fork_id [lindex $_el_fork_stack [expr $len -1 ]] # delete last item in stack set _el_fork_stack [lreplace $_el_fork_stack end end] # return last value of fork_id from stack return $fork_id } } return "" } # # Subroutine to remove first char from string and return substring # # proc _el_strip_char { string char } { #puts "s->$string||$char||" regsub -- $char $string "" stringb #puts "s->$stringb||$char||" return $stringb } # # Find a color in a comment line # # proc find_color { str } { upvar expectlite::el_color el_color set fcolor "" # detect first word of comment, if it is a color, then so use it set l_str [split $str] set first_word [lindex $l_str 0 ] #puts "------------------>$l_str|$first_word|[lsearch [array names el_color] $first_word ]|" if {[lsearch [array names el_color] $first_word ] != -1} { set fcolor $first_word } return $fcolor } # # Proc to allow passing of arguments to Include file as constants # preserves any constants already defined, and restores them # after include file returns # # preserve const var=value and return preserved values as list {{var} {value}...} # proc _el_preserve_const { varvalue_list } { upvar expectlite::cli_namespace cli_namespace set out_list {} # tease apart in list foreach x $varvalue_list { # pull values off of list set var [lindex $x 0] set value [lindex $x 1] # is there a constant with this name? if { [info exists cli_namespace($var) ] } { #preserve value of constant lappend out_list "{$var} {$cli_namespace($var)}" set cli_namespace($var) $value } else { # put empty value on list lappend out_list "{$var} {}" set cli_namespace($var) $value } }; #foreach #puts "pppppp>$out_list" return $out_list } # # restore const var=value from list {{var} {value}...} # proc _el_restore_const { varvalue_list } { upvar expectlite::cli_namespace cli_namespace # tease apart in list foreach x $varvalue_list { # pull values off of list set var [lindex $x 0] set value [lindex $x 1] # is there a constant with this name? if { [info exists cli_namespace($var) ] } { #restore value of constant if { $value != {} } { set cli_namespace($var) $value } else { unset cli_namespace($var) } } }; #foreach } # # Parse arg string for var=value in list {{var} {value}...} # proc _el_parse_var_value { varvalue_list } { set out_list {} # create new list set in_list {} set val_str "" # Parse list to be var-value and directives pairs # append to list in format {var=} {value with spaces} foreach x $varvalue_list { #puts "==x>$x|$val_str|" if { [regexp {[a-zA-Z0-9_]+[=]} $x ] == 1 } { # handle var=val pairs if { $val_str != ""} { lappend in_list [string trimright $val_str " "] set val_str "" } set y [ split $x "=" ] #puts "==y>$y" set val_str [lindex $y 1] lappend in_list "[lindex $y 0]=" } elseif { [regexp {[*][A-Z0-9_]+} $x ] == 1 } { # handle directives if { $val_str != ""} { lappend in_list [string trimright $val_str " "] set val_str "" } lappend in_list $x lappend in_list {} } else { set val_str "$val_str $x" } } # append last value part if { $val_str != ""} { lappend in_list [string trimright $val_str " "] #puts "in_list+++>$in_list|$val_str" } #puts "==in_list>$in_list" # walk through list creating {{var} {value}} set i 0 if { [llength $in_list] > 0 } { foreach x $in_list { # is passed value in format 'var=' if { [regexp {[a-zA-Z0-9_]+[=]} $x ] == 1 } { set var_value_l [split $x "=" ] set var [lindex $var_value_l 0] set value [lindex $in_list [expr $i + 1]] #set value [lindex $var_value_l 1] lappend out_list "{$var} {$value}" #puts ">>>$x>>$var=$value" } incr i }; #foreach } # walk through list to format directives as {{*DIRECTIVE} {}} # TODO implement directive processing in the future if { [llength $out_list ] > 0 } { return $out_list } else { return {} } }; #proc # # Prints a comment line (begins with a ';') # # proc print_comment_line { } { upvar expectlite::el_color el_color upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::timeout_line timeout_line upvar expectlite::comment_line comment_line upvar expectlite::INFO INFO # initialize font color if { $comment_line != "" } { set fcolor [find_color $comment_line] if { $fcolor != "" } { # remove first word regsub "$fcolor" $comment_line "" comment_line } } # print ';' printable comment if { $comment_line != "" } { #puts "\n$comment_line\n" cputs "\n$comment_line\n" $fcolor set comment_line "" } # print new expect timeout value (if needed) if { $timeout_line != "" } { if {$INFO} { cputs "\n$timeout_line\n" $_el_info_color } set timeout_line "" } } # # Prints all user vars and constants # Called by *SHOW VARS & IDE v # proc show_vars { } { upvar expectlite::user_namespace user_namespace upvar expectlite::cli_namespace cli_namespace upvar expectlite::arg0 arg0 upvar expectlite::_el_buf _el_buf upvar expectlite::_el _el set blank " " set blank_len [string length $blank] set var_list [array names user_namespace] set var_list_sorted [lsort $var_list] cputs "DEBUG Info: Printing all expect-lite variables" "none" # print internal vars if { [ info exists cli_namespace($arg0) ] } { set ii_len [string length $arg0] set ii_blank [string range $blank 1 [expr $blank_len - $ii_len]] set script_name $cli_namespace($arg0) if { $_el_buf(stack) > 1 } { if { [info exists _el(include_file_name) ] } { set script_name "$script_name-> ~$_el(include_file_name)" } } cputs "Var:arg0 $ii_blank Value:$script_name" "none" } foreach ii $var_list_sorted { # create aligned columns set ii_len [string length $ii] set ii_blank [string range $blank 1 [expr $blank_len - $ii_len]] # is a constant overiding the var? if { [info exists cli_namespace($ii) ] } { set iii_len [string length $user_namespace($ii)] set iii_blank [string range $blank 1 [expr $blank_len - $iii_len]] #puts "iii----->$user_namespace($ii)|$iii_blank|$blank_len|$iii_len" } # don't print array initialization var (zero) if { $ii != 0 } { if { [info exists cli_namespace($ii) ] } { # print var, value, Const cputs "Var:$ii $ii_blank Value:$user_namespace($ii) $iii_blank Const:$cli_namespace($ii)" none } else { # print var, value cputs "Var:$ii $ii_blank Value:$user_namespace($ii)" none } } } } # # Prints all expect-lite environment # Called by IDE e # proc show_environment { } { upvar expectlite::user_namespace user_namespace upvar expectlite::cli_namespace cli_namespace upvar expectlite::arg0 arg0 upvar expectlite::_el_buf _el_buf upvar expectlite::_el _el # clean up names for printout global env timeout upvar expectlite::INFO INFO upvar expectlite::EXP_INFO EXP_INFO upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_eols _el_eols upvar expectlite::_el_current_session CURRENT_FORK_SESSION upvar expectlite::_el_infinite_loop INFINTE_LOOP_COUNT upvar expectlite::NOFAIL NOFAIL upvar expectlite::TIMESTAMP TIMESTAMP upvar expectlite::NOINTERACT NOINTERACT upvar expectlite::NOINCLUDE NOINCLUDE upvar expectlite::LOG LOG upvar expectlite::cli_namespace cli_namespace upvar expectlite::el_log_ext LOG_EXT upvar expectlite::SHOW_HELP SHOW_HELP upvar expectlite::DVARPROMPT DVPROMPT upvar expectlite::remote_shell remote_shell #generic print utility proc print_item { item value } { upvar env_list_sorted env_list_sorted set blank " " set blank_len [string length $blank] # allow exceptions - print numbers set exception_list { timeout INFINTE_LOOP_COUNT fuzzy_range } # create aligned columns set ii_len [string length $item] set ii_blank [string range $blank 1 [expr $blank_len - $ii_len]] if { [string is integer $value ] } { set val "on" if { $value == 0 } { set val "off"} # print on/off if value is a flag, otherwise print value switch -glob $value { 0 - 1 - 10 { # allow exceptions to print numbers if { [ lsearch $exception_list $item ] > -1 } { cputs "$item $ii_blank $value" "none" } else { cputs "$item $ii_blank $val" "none" } } default { cputs "$item $ii_blank $value" "none" } } } else { # $item is a string value cputs "$item $ii_blank $value" "none" } } # additional values set timeout $::timeout set USER_DEFINED_PROMPT $_el(prompt) # fail script if { [info exists _el(fail_script) ] } { set FAIL_SCRIPT $_el(fail_script) } else { set FAIL_SCRIPT "none" } # remote shell **SHELL set REMOTE_SHELL $remote_shell if { $REMOTE_SHELL == "" } { set REMOTE_SHELL "none" } # handle EOLS if { $_el_eols == "\n" } { set EOLS LF } else { set EOLS CRLF} set fuzzy_range $_el(fuzz) set env_list { INFO EXP_INFO WARN DEBUG CURRENT_FORK_SESSION \ INFINTE_LOOP_COUNT NOFAIL TIMESTAMP NOINTERACT NOINCLUDE LOG LOG_EXT \ DVPROMPT timeout USER_DEFINED_PROMPT EOLS fuzzy_range FAIL_SCRIPT \ REMOTE_SHELL } set env_list_sorted [lsort $env_list] cputs "DEBUG Info: Printing expect-lite directives/environment" "none" # print header print_item Environment: Value: foreach ii $env_list_sorted { # double dereference $item to get value using [set $item] print_item $ii [set $ii] # print log file name if used if { $ii == "LOG" } { set log_file [log_file -info] if { $log_file != "" } { set log_file [lindex [split $log_file] 1] print_item LOG_FILE $log_file } } } # Shell Env set env_list { EL_REMOTE_HOST EL_CMD_FILE EL_USER_DIR EL_CONNECT_METHOD \ EL_CONNECT_USER EL_CONNECT_PASS EL_LOG_EXT EL_INFINITE_LOOP \ EL_DELAY_WAIT_FOR_HOST EL_SHELL } set env_list_sorted [lsort $env_list] foreach ii $env_list_sorted { if { [info exist env($ii) ]} { print_item $ii $env($ii) } else { #print_item $ii "none" } } } # # Resolves user vars to values, only if there isn't a Constant with the same name # Constants are always given preference over user vars (defined in the script) # returns value of var if known, or replaces $var format (for shell vars) # proc resolve_var_sub var { upvar expectlite::user_namespace user_namespace upvar expectlite::cli_namespace cli_namespace upvar expectlite::_el_info_color _el_info_color upvar expectlite::INFO INFO upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG if { $var != "" } { set append_value 1 # we have the var set user_var $var #puts "var>$user_var" # Give priority over Constants, only assign Vars if Constant not present if { [catch {set user_value $cli_namespace($user_var)}] } { if { [catch {set user_value $user_namespace($user_var)}] } { # go quietly into the night #puts stderr "VAR NOT FOUND: |$user_var|" # unknown var set append_value 0 } } else { # Show all constant substitutions if in DEBUG if {$DEBUG} { cputs "INFO: CONST FOUND: $user_var = $cli_namespace($user_var)" $_el_info_color } # Show non ENV constant substitutions in INFO if { $INFO==1 && [regexp {^EL_} $user_var]!=1 } { cputs "INFO: CONST FOUND: $user_var = $cli_namespace($user_var)" $_el_info_color } } if { $append_value } { #puts "u_v>$var=$user_value" # only append valid vars return $user_value } else { # if unknown var, be sure to put it back on line with a '$' in front for shell vars return "\$$var" } } else { return "" } } # # A rather complicated subroutine (sorry) which parses out user vars in the script # The sep_list defines what chars are _not_ in vars # returns value of var, or $var if shell var # # This function uses a two stage TCL command "split" to parse the expect-lite variables # For example, the following line requires parsing: "mount$this$that#other" # 1) The first stage split will split on '$' resulting in "mount this that#other" # 2) "mount" will be discarded, since it is the first part, and not preceeded with a '$' # 3) The remaining line segments (in a TCL list) will go to the second split stage which # cycles thru a known list of characters signaling the end of a variable name (sep_list) # 4) "this" passes the second stage, and is passed to proc resolve_var_sub for resolution # 5) "that#other" will be split again into "that other" in the second split stage # 6) Only the first line segment after the second stage split is sent to proc resolve_var_sub # for resolution (of key value pairs) # In this example it would be "that" which is sent for resolution # 7) The entire line is reassembled after var resolution, and returned # proc parse_var { var sep } { # parses the string passed, separating out the Vars and passing them to resolve_var_sub to be resolved # List of Chars which define the end of a Var set sep_list { ! @ # % & * / { } \\ ( ) . [ ] = ? \" : ; - , | < >} #puts "v>$var|s>$sep" set resolved_line "" set var_list [ split $var $sep] #puts "vl>$var_list|sep>$sep" # If only 1 var on the line if { [llength $var_list] == 1 } { if { $sep == "$" } { #puts "one only" # return first chunk which is NOT a var in var_list append resolved_line $var } else { append resolved_line [resolve_var_sub $var] } } else { # First time in (no recursion) if { $sep == "$" } { append resolved_line [lindex $var_list 0] } else { # Dereferences Vars on First time through the var_list #puts "look here" append resolved_line [resolve_var_sub [lindex $var_list 0]] } #puts "vl>$var_list" for {set j 1} {$j<[llength $var_list]} {incr j} { set var_only 1 # are there other strange chars in the var? # use low_water_marker to find closest one # FIXME: limits var length to less that 255 set low_water_marker 255 foreach k $sep_list { set odd_char_pos [string first $k [lindex $var_list $j]] if { $odd_char_pos > -1 } { if { $odd_char_pos < $low_water_marker } { set low_water_marker $odd_char_pos set s $k } set var_only 0 } #puts "k>[string first $k [lindex $var_list $j]]]" } if { $var_only } { # "var only" no other strange chars found if { $sep == "$" } { #puts "vo>[lindex $var_list $j]|j>$j" append resolved_line [resolve_var_sub [lindex $var_list $j]] } else { #puts "j>$j|sep>$sep" # add literals back to the line (in a recursed call) append resolved_line $sep[lindex $var_list $j] } } else { #puts "j>$j|recurse!" # Recursion Call with smaller chunck - splits known var with "extra" chars # and make sure the var length isn't zero if { ($sep == "$") && ($low_water_marker != 0) } { append resolved_line [parse_var [lindex $var_list $j] $s] } else { append resolved_line $sep[lindex $var_list $j] } } #puts "j>$j|val>$resolved_line" } } #puts "r>$resolved_line" return $resolved_line } # end of parse_var # # Buffer management functions # A buffer is used to permit random access to the command script # This enables looping, but setting the buffer pointer to a # previous line in the script # The conditional/jump mechanism will use this method for looping # # # Opens command script and reads into buffer (tcl list) # Returns buffer # proc _el_buffer {{cmd_file ""} {in_list ""}} { upvar expectlite::_el_buf _el_buf upvar expectlite::_el_err_color _el_err_color # generic get next proc to get from file or list proc get_next_line {} { upvar cmd_file cmd_file upvar infile infile upvar in_list in_list upvar listptr listptr upvar buf_line buf_line if {$cmd_file != ""} { set rtncode [gets $infile buf_line] return $rtncode } if {$in_list != ""} { if { $listptr <= [llength $in_list] } { # read line off of in_list set buf_line [ lindex $in_list $listptr ] incr listptr set rtncode 1 } else { set rtncode -1 } return $rtncode } # should not make it here, but if so, stop return -1 }; #end proc # sets line buffer to start at line 1, rather than 0, helps pasting lines in IDE set line_buffer {#} set help_buffer {} set listptr 0 # read help flag set read_help 0 if {$cmd_file != ""} { # Protect against no file to read if { [ catch { set infile [open $cmd_file r ] } error] } { puts stderr "Unable to open cmd/include_file \n $error" exit 1 } } while { -1 != [ get_next_line ]} { # meta_line used to hold additional info about line, for line blocks set meta_line -1 # remove leading white space on line (permitting indentation regsub {^[ \t]+} $buf_line {} buf_line #trim white space at end of labels if { [ regexp {^%} $buf_line ] } { # remove leading white space on line (permitting indentation regsub {[ \t]+$} $buf_line {} buf_line } # pad back slash at end of line - do not escape curly list item if { [ regexp {\\$} $buf_line ] } { # remove leading white space on line (permitting indentation regsub {\\$} $buf_line {\\ } buf_line } # process block lines ] pop if { [regexp {^[\]]} $buf_line ] && $read_help == 0 } { set meta_line_blob [join [_el_buffer_block_pop ]] # poor man's lassign (8.5 feature) - unpack list into vars foreach {meta_line meta_line_type} $meta_line_blob {break} # update meta-line of '[' line # preserve line-data set t_line_data [lindex $line_buffer $meta_line 0] #puts "======>$buf_line | $meta_line | $t_line_data | $meta_line_type" # update [ line meta-data with valid line number (read: not -1) if { $meta_line > 0 } { if {[ catch { lset line_buffer $meta_line "{$t_line_data} {[llength $line_buffer]}"} error ]} { cputs "expect-lite: ERROR: expect-lite BUG.. \n$error\n" $_el_err_color exit -1 } } # is the popped line an if statement? if { $meta_line_type == "if" } { set meta_line [expr [llength $line_buffer] + 1] # if block lines is "else" ]::[ then push if { [regexp {^\][ ]*::[ ]*\[[ \t]*$} $buf_line ]} { # then push "else" _el_buffer_block_push [concat "[llength $line_buffer] $meta_line_type"] } }; #if meta-if } # process block lines [ push if { [regexp {^[\[]} $buf_line ] } { _el_buffer_block_push [concat "[llength $line_buffer] \"while\" "] } # process ?if block lines [ push if { [regexp {^\?.+\?[ ]*\[} $buf_line ] ||[regexp {^\?.+\?.*::[ ]*\[} $buf_line ]} { _el_buffer_block_push [concat "[llength $line_buffer] \"if\" "] } # check if help lines are in file if { [ regexp {^;;;} $buf_line ] && $read_help == 1 } { set read_help 0 # stip three semi-colons regsub {;;;} $buf_line {} buf_line # add last line of help lappend help_buffer "$buf_line" } elseif { [ regexp {^;;;} $buf_line ] && $read_help == 0 } { set read_help 1 } # add line to buffer if { $read_help == 1 } { # place help lines into help_buffer # stip three semi-colons regsub {;;;} $buf_line {} buf_line #puts "==add help line==>[llength $line_buffer] | {$buf_line} {$meta_line}" lappend help_buffer "$buf_line" } elseif { [regexp {^[$%*+:-@!~'\[\]-]} $buf_line ] } { # don't read in blank lines - make sure to include all needed lines [>[llength $line_buffer] | {$buf_line} {$meta_line}" lappend line_buffer "{$buf_line} {$meta_line}" } } if {$cmd_file != "" } { close $infile } #puts "-> $line_buffer|[llength $line_buffer] " # push new buffer stack incr _el_buf(stack) # save the buffer set _el_buf($_el_buf(stack)) $line_buffer # save the help buffer set _el_buf(help) $help_buffer # initialize the buffer pointer - points to the line no in the buffer set _el_buf($_el_buf(stack),ptr) 0 # clear the block stack _el_buffer_block_clear # return the stack ID of this buffer return $_el_buf(stack) } # # Clears buffer but retains stack pointer # # proc _el_buffer_stack_clear { stack_number } { upvar expectlite::_el_buf _el_buf upvar expectlite::_el _el # set buffer to empty list if { [info exists _el_buf($stack_number) ] } { set _el_buf($stack_number) {} # pop buffer stack incr _el_buf(stack) -1 } } # # Reads buffer as if it were a file, returning a line from the buffer # # proc _el_buffer_read { line_no buf_stack {line_info_field 0} {debug 0}} { upvar expectlite::_el_buf _el_buf # line_info #set line_info_field 0 if { $line_info_field == 0 } { #puts " $line_no | $buf_stack | $_el_buf($buf_stack,ptr) | [lindex $_el_buf($buf_stack) $line_no ] " } # Do not read past end of buffer if { $line_no < [llength $_el_buf($buf_stack)] } { # use lindex to return first field in line_no set buf_line [lindex $_el_buf($buf_stack) $line_no $line_info_field] # remove escaped braces regsub -all {\\([{}])} $buf_line {\1} buf_line if {$debug} { # show debug info, line number, line & meta-data set buf_line "$line_no | $buf_stack | [lindex $_el_buf($buf_stack) $line_no ] " } return $buf_line } else { return -1 } } # # Reads buffer, prints n lines # # proc _el_buffer_show { num_of_lines buf_stack {debug 0}} { upvar expectlite::_el_buf _el_buf upvar expectlite::_el_info_color _el_info_color #puts " $num_of_lines | $buf_stack | $_el_buf($buf_stack,ptr) | [expr $_el_buf($buf_stack,ptr) + $num_of_lines] " # don't print lines which are not in the buffer (have -1) proc print_line { line } { #global _el_info_color upvar expectlite::_el_info_color _el_info_color if { $line != -1 } { cputs "$line" $_el_info_color } } # end print_line if {$num_of_lines > 0} { cputs "Printing next $num_of_lines line(s) of script:" $_el_info_color set num_of_lines [expr $num_of_lines + 1 ] for {set n [expr $_el_buf($buf_stack,ptr) +1]} {$n<[expr $num_of_lines + $_el_buf($buf_stack,ptr)]} {incr n} { print_line [ _el_buffer_read $n $buf_stack 0 $debug ] } } elseif {$num_of_lines < 0} { cputs "Printing last [expr {abs($num_of_lines)}] line(s) of script:" $_el_info_color for {set n [expr $_el_buf($buf_stack,ptr) + $num_of_lines] } {$n < $_el_buf($buf_stack,ptr)} {incr n } { print_line [ _el_buffer_read $n $buf_stack 0 $debug ] } } else { # print current line cputs "Printing current line of script:" $_el_info_color print_line [ _el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack ] } } # # Reads buffer, returns list of items maching $obj # # proc _el_buffer_get_obj { buf_stack {obj "\\\$"}} { upvar expectlite::_el_buf _el_buf upvar expectlite::_el_info_color _el_info_color set out_list {} #puts "obj>>>$obj|" foreach line $_el_buf($buf_stack) { if { [ regexp "^$obj" [lindex $line 0 ] ] } { lappend out_list [lindex $line 0] } #puts "ddd>$line" } #puts "out_list>$out_list" return $out_list } # # Reads buffer, prints contigous help lines # # proc _el_buffer_show_help { buf_stack {obj {^;;;} }} { upvar expectlite::_el_buf _el_buf upvar expectlite::_el_info_color _el_info_color upvar expectlite::WARN WARN set out_list {} #puts "obj>>>$_el_buf(help)|" #check that there is text in the help buffer if { $_el_buf(help) != {} } { set i 0 # display text in help buffer while { $i < [llength $_el_buf(help)] } { set buf_line [lindex $_el_buf(help) $i] puts "\t$buf_line" incr i } ;#end while } }; #end proc # # Goto buffer line number # # proc _el_buffer_goto { line_no buf_stack } { upvar expectlite::_el_buf _el_buf # Do not set past end of buffer if { $line_no >= 0 && $line_no <= [llength $_el_buf($buf_stack)] } { set _el_buf($_el_buf(stack),ptr) $line_no } } # # clears block stack # # proc _el_buffer_block_clear { } { upvar expectlite::_el_buf_block_stack stack set stack {} } # # Pushes '[' line in buffer # # proc _el_buffer_block_push { meta_blob} { upvar expectlite::_el_buf_block_stack stack #puts "=====>$line_no | $type | $stack " # meta_blob is line_no + type lappend stack $meta_blob } # # pops '[' line in buffer and returns line number + type # # proc _el_buffer_block_pop { } { upvar expectlite::_el_buf_block_stack stack if { [llength $stack ] != 0 } { set meta_blob [lindex $stack end] #puts "====stack==>$stack | $meta_blob" # delete last item (most recent) in stack set stack [lreplace $stack end end] #puts "====stack==>$stack" return $meta_blob } else { return -1 } } # # Buffer Search # Searches buffer from line_ptr down to end of buffer # If search fails, search will 'wrap' and continue from beginning of buffer # This allows duplicate search items in the buffer, finding the first succeding one # However search items used as looping labels should be unique! # proc _el_buffer_search {line_ptr line_search buf_stack} { upvar expectlite::_el_infinite_loop _el_infinite_loop upvar expectlite::el_color el_color upvar expectlite::INFO INFO upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG upvar expectlite::EXP_INFO EXP_INFO upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::_el_buf _el_buf # search down first if {$INFO} { # start INFO color if {$_el_comment_color == "none"} { puts -nonewline $el_color($_el_info_color) } puts -nonewline "\nJumping to label" } # get a list of pointers which match search of first field (line-data) if { [exp_version] >= "5.44.0" } { set _ptr_list [lsearch -all -index 0 $_el_buf($buf_stack) "$line_search"] } else { # TCL 8.4 does not support lsearh -index set line_search_glob "\{$line_search*" set _ptr_list [lsearch -all $_el_buf($buf_stack) "$line_search_glob"] } if { $_ptr_list == {} } { if {$WARN} { puts -nonewline "\n\nWARNING: Label not found" } # signal label not found set _ptr -1 } else { # give preference to search backwards set i -1 foreach ptr $_ptr_list { if { $ptr < $line_ptr } { incr i } } if { $i == -1} { # not found then search forwards foreach ptr $_ptr_list { if { $ptr > $line_ptr } { incr i ; break } } } set _ptr [lindex $_ptr_list $i] # decrement infinite loop detector incr _el_infinite_loop -1 if { $_el_infinite_loop < 1 } { # return search not found cputs ":$line_search\n\n\nERROR: Infinite Loop Detected!!\n\n" $_el_err_color return -2 } } # put final field on info line if {$INFO} { cputs ":$line_search\n" $_el_info_color } #puts "|$line_search|$line_ptr|$_ptr_list|$_ptr|[lindex $_el_buf($buf_stack) 152]|" return $_ptr } # # End of Buffer management functions # # # Infinite loop detection # # proc _el_check_infinite_loop { } { upvar expectlite::_el_infinite_loop _el_infinite_loop upvar expectlite::_el_err_color _el_err_color #cputs "=======>infinite_loop=$_el_infinite_loop" $_el_err_color # decrement infinite loop detector incr _el_infinite_loop -1 if { $_el_infinite_loop < 0 } { # return search not found cputs "\n\nERROR: Infinite Loop Detected!\n\n" $_el_err_color return -2 } return 0 } # # calculate timestamp with miliseconds # # proc _el_timestamp { } { upvar expectlite::_el _el set date [clock clicks -milliseconds ] # separate milisecs from seconds set ms [expr $date % 1000] set date [expr int($date / 1000)] set date_str [clock format $date -format $_el(ts_fmt)] #pad left with zeros set ms [format "%03d" $ms] #add milisecs into formatted string regsub {\$ms} $date_str "$ms" date_str return $date_str } # # Set Global expect-lite Directives # # proc _el_global_directive { g_dir_str } { global timeout upvar expectlite::INFO INFO upvar expectlite::EXP_INFO EXP_INFO upvar expectlite::WARN WARN upvar expectlite::DEBUG DEBUG upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_eols _el_eols upvar expectlite::_el_fork _el_fork upvar expectlite::_el_current_session _el_current_session upvar expectlite::_el_infinite_loop _el_infinite_loop upvar expectlite::NOFAIL NOFAIL upvar expectlite::_el _el upvar expectlite::TIMESTAMP TIMESTAMP upvar expectlite::NOINTERACT NOINTERACT upvar expectlite::NOINCLUDE NOINCLUDE upvar expectlite::LOG LOG upvar expectlite::arg0 arg0 upvar expectlite::cli_namespace cli_namespace upvar expectlite::el_log_ext el_log_ext upvar expectlite::SHOW_HELP SHOW_HELP upvar expectlite::DVARPROMPT DVARPROMPT switch -glob $g_dir_str { "\\*INFO" { # Turn on INFO logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr INFO } "\\*EXP_INFO" { # Turn on Expect INFO logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr EXP_INFO } "\\*WARN" { # Turn on WARN logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr WARN } "\\*DEBUG" { # Turn on DEBUG logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr DEBUG } "\\*LOG*" { # Turn on LOG logging # set default log file name to script name+.log (e.g. $el_log_ext) if { [info exist cli_namespace($arg0)] } { set fname "$cli_namespace($arg0)$el_log_ext" } else { # use a default name set fname "expect-lite$el_log_ext" } # remove excess spaces in log string regsub {[ ]+} $g_dir_str " " g_dir_str set log_list [split $g_dir_str] if { [llength $log_list] > 2 } { if {$WARN} { cputs "\n\nWarning: LOG: Too Many Parameters: $g_dir_str\n" $_el_warn_color } # invalid *LOG command, exit this function return 1 } elseif {[llength $log_list] == 2 } { #if { $LOG == 0 } { set LOG 1 } # get log filename set fname [lindex $log_list 1] # check for *LOGAPPEND if { [regexp {LOGA} [lindex $log_list 0]] == 1 } { set LOG -1 # close any running log log_file } } elseif {[llength $log_list] == 1 } { set LOG 1 if { [regexp {LOGA} [lindex $log_list 0]] == 1 } { set LOG -1 # close any running log log_file } } if { $SHOW_HELP } { # don't do any thing with the LOG set LOG -10 } switch -- $LOG { 1 - 0 { # open log file # check of log file exists, and issue warning if {[file exists $fname] == 1} { if {$WARN} { cputs "expect-lite: Warning: Overwriting $fname " $_el_warn_color } } # close running log log_file # make sure log file is writable if {[ catch { log_file; log_file -noappend "$fname"} error ]} { cputs "expect-lite: ERROR: $error\n" $_el_err_color return -1 } set LOG 1 } -1 { # Log was already open, so just append to log file if {[ catch { log_file -a "$fname"} error ]} { cputs "expect-lite: ERROR: $error\n" $_el_err_color return -1 } set LOG 1 if {$INFO} { cputs "\nexpect-lite: Appending to log file: $fname" $_el_info_color } } 10 { #do nothing, overiden at CLI } -10 { #do nothing, overiden at CLI } } ; # end switch cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } "\\*NOLOG" { # Turn off LOG logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color # do not disable if CLI has enabled if {$LOG != 10 && $LOG != -10 } { set LOG -1 # turn off log file log_file } } "\\*NOINFO" { # Turn off INFO logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color # do not disable if CLI has enabled if {$INFO < 10 } { set INFO 0 } } "\\*NOEXP_INFO" { # Turn off Expect INFO logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color if {$EXP_INFO < 10 } { set EXP_INFO 0 } } "\\*NOWARN" { # Turn off WARN logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color # do not disable if CLI has enabled if {$WARN < 10 } { set WARN 0 } } "\\*NODEBUG" { # Turn off DEBUG logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color # do not disable if CLI has enabled if {$DEBUG < 10 } { set DEBUG 0 } } "\\*NOCOLOR" - "\\*NOCOLOUR" { # Turn off Color logging cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color # set INFO color set _el_info_color none # set WARN color set _el_warn_color none # set ERROR color set _el_err_color none # set global color set _el_comment_color none } "\\*NOTIMESTAMP" { # Turn off TIMESTAMP logging if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } # do not disable if CLI has enabled if {$TIMESTAMP != 10 } { set TIMESTAMP 0 } } "\\*PASS" { # Terminate but Pass Test cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color ### Terminate the test with a pass if {$INFO} {cputs "\n\n##Overall Result: PASS \n\n" $_el_info_color } exit 0 } "\\*TERM*" { # Terminate but Pass Test cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color set term_list [split $g_dir_str] #puts "=====>$term_list" if { [llength $term_list] > 2 } { if {$WARN} { cputs "\n\nWarning: TERM: Too Many Names: $g_dir_str\n" $_el_warn_color } # invalid *TERM command, exit this function return 1 } elseif {[llength $term_list] == 2 } { # set the term_id to the passed value set term_id [lindex $term_list 1] # check that term_id is a number between 0-255 if {[ catch { string is integer $term_id } error ]} { #hmm term_id is not a number cputs "\n\nWarning: TERM: non-zero return code: $g_dir_str\n$error" $_el_warn_color } else { #term_id looks to be a number if { $term_id > -1 && $term_id < 256 } { if { $term_id > 0 } { ### Terminate the script with a non zero if {$INFO} {cputs "\n\n##Overall Result: TERM=$term_id \n\n" $_el_err_color } } else { ### Terminate the script with a pass if {$INFO} {cputs "\n\n##Overall Result: TERM=$term_id \n\n" $_el_info_color } } exit $term_id } else { #hmm term_id is out of range cputs "\n\nWarning: TERM: return code is no between 0 and 255: $g_dir_str\n" $_el_warn_color } } } elseif {[llength $term_list] == 1 } { # no arguments to *FORK, then display current session name ### Terminate the test with a pass if {$INFO} {cputs "\n\n##Overall Result: PASS \n\n" $_el_info_color } exit 0 } } "\\*FAIL" { # Terminate and Fail Test cputs "\nexpect-lite directive: $g_dir_str " $_el_err_color if { $NOFAIL } { # set test to fail return 0 } else { # NOFAIL not set, fail right now return 2 } } "\\*EOLS LF" { # Set End of Line Sequence to LF if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } set _el_eols "\n" } "\\*EOLS CRLF" { # Set End of Line Sequence to CRLF if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } set _el_eols "\r\n" } "\\*DVPROMPT" { # Dyn Var Capture requires prompt (default) if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } # do not change if CLI has enabled if {$DVARPROMPT < 10 } { incr DVARPROMPT } } "\\*NODVPROMPT" { # Dyn Var Capture does not require prompt if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } # do not change if CLI has enabled if {$DVARPROMPT < 10 } { set DVARPROMPT 0 } } "\\*SHOW VARS" { # Show expect-lite variables cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color show_vars } "\\*SHOW ENV" { # Show expect-lite variables cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color show_environment } "\\*INTERACT" { # place into expect interact mode # Skip interact if in Library mode # Jump to interact if { $NOINTERACT == 0 } { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color instant_interact_sig } elseif {$NOINTERACT > 0} { cputs "\nSkipping expect-lite directive: $g_dir_str " $_el_info_color } } "\\*FORK*" { # Spawn/Switch to a new session set fork_list [split $g_dir_str] if { [llength $fork_list] > 2 } { if {$WARN} { cputs "\n\nWarning: FORK: Too Many Names: $g_dir_str\n" $_el_warn_color } # invalid *FORK command, exit this function return 1 } elseif {[llength $fork_list] == 2 } { # set the fork_id to the passed value set fork_id [lindex $fork_list 1] # store current eols in current session fork_context set _el_fork($_el_current_session,eols) $_el_eols } elseif {[llength $fork_list] == 1 } { # no arguments to *FORK, then display current session name set fork_id $_el_current_session } # spawn/switch to fork_id session set _el_current_session [session_id_manager $fork_id] # set eols from new fork_id_context set _el_eols $_el_fork($_el_current_session,eols) #kick the prompt protected_send "$_el_eols" } "\\*NOFAIL" { # Never fail the test cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr NOFAIL } "\\*NOINTERACT" { # Never stop at *INTERACT (good for regression) cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr NOINTERACT } "\\*NOINCLUDE" { # Do not include files -- backward compatiblity with 4.1 behaviour cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color incr NOINCLUDE } } # end switch glob # set values with a parameter (using regex) switch -regexp $g_dir_str { "\\*INFINITE_LOOP [0-9]+" { # expect-lite infinite loop value cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color set varlist [split $g_dir_str ] set _el_infinite_loop [lindex $varlist 1] } "\\*TCL .+" { #native TCL command for library use if { [info exist ::EL_LIBRARY] } { set ::_el_tcl_cmd [string trim $g_dir_str "*TCL "] # preserve timeout set el_timeout $::timeout # disable timeout during function call set timeout 0 if { $DEBUG } { cputs "EL TCL CMD>$::_el_tcl_cmd" $_el_debug_color } # provide catch protection, and run tcl_cmd if {[ catch { uplevel #0 {eval $::_el_tcl_cmd }} error ]} { cputs "ERROR: Expect: \'\n$::_el_tcl_cmd\' \n$error\n" $_el_err_color } # restore timeout set timeout $el_timeout } } "\\*TIMESTAMP" { #Issue Time Stamps with each > or >> if {$INFO} { cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color } set ts_list [split $g_dir_str] if { [llength $ts_list] > 2 } { if {$WARN} { cputs "\n\nWarning: TIMESTAMP: Too Many Parameters: $g_dir_str\n" $_el_warn_color } # invalid *TIMESTAMP command, exit this function return 1 } elseif {[llength $ts_list] == 2 } { # set timestamp on & format string set TIMESTAMP 1 set ts_format [lindex $ts_list 1] switch -glob $ts_format { "YMD" - "ISO" { set _el(ts_fmt) "\n\[ %Y-%m-%d %T.\$ms \] " } "MDY" { set _el(ts_fmt) "\n\[ %D %T.$ms \] " } "DMY" { set _el(ts_fmt) "\n\[ %d-%m-%Y %T.\$ms \] " } default { # set a ISO as default if {$WARN} { cputs "\n\nWarning: unknown format, using YMD" $_el_warn_color } set _el(ts_fmt) "\n\[ %Y-%m-%d %T.\$ms \] " } } } elseif {[llength $ts_list] == 1 } { # no arguments to *TIMESTAMP, default to ISO set TIMESTAMP 1 # use YMD format as default set _el(ts_fmt) "\n\[ %Y-%m-%d %T.\$ms \] " } } ; #timestamp } # end switch regex return 1 } # # Heart of expect-lite, reads through script file, and takes appropriate action (based on switch statement) # # proc _el_script_exec {{cmd_file ""} {buf_stack ""}} { # default parameters: cmd_file is "" in library mode # buf_stack is used when el_script is called recursively (e.g. include) global expect_out timeout spawn_id upvar expectlite::remote_host remote_host upvar expectlite::_out _out upvar expectlite::_out_nowait _out_nowait upvar expectlite::_in _in upvar expectlite::_in_noregex _in_noregex upvar expectlite::_in_fuzzy _in_fuzzy upvar expectlite::_not_in _not_in upvar expectlite::_timeout _timeout upvar expectlite::_sleepchar _sleepchar upvar expectlite::_var _var upvar expectlite::_cond _cond upvar expectlite::_cond_regex _cond_regex upvar expectlite::_cond_else _cond_else upvar expectlite::_label _label upvar expectlite::_el _el upvar expectlite::_el_buf _el_buf upvar expectlite::_exec _exec upvar expectlite::_stdout_comment _stdout_comment upvar expectlite::_stdout_comment_nobuf _stdout_comment_nobuf upvar expectlite::_include _include upvar expectlite::_include_fail _include_fail upvar expectlite::comment_line comment_line upvar expectlite::timeout_line timeout_line upvar expectlite::timeout_multiplier timeout_multiplier upvar expectlite::WARN WARN upvar expectlite::delay_wait_for_host delay_wait_for_host upvar expectlite::cli_namespace cli_namespace upvar expectlite::user_namespace user_namespace upvar expectlite::user_dir user_dir upvar expectlite::_el_infinite_loop _el_infinite_loop upvar expectlite::_incr_var _incr_var upvar expectlite::_decr_var _decr_var upvar expectlite::connect_method connect_method upvar expectlite::_el_fork _el_fork upvar expectlite::DEBUG DEBUG upvar expectlite::INFO INFO upvar expectlite::arg0 arg0 upvar expectlite::_el_comment_color _el_comment_color upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_eols _el_eols upvar expectlite::el_color el_color upvar expectlite::EXP_INFO EXP_INFO upvar expectlite::_el_current_session _el_current_session upvar expectlite::NOFAIL NOFAIL upvar expectlite::NOINCLUDE NOINCLUDE upvar expectlite::TIMESTAMP TIMESTAMP upvar expectlite::DVARPROMPT DVARPROMPT set prev_line "" set comment_line "" set timeout_line "" set _el_fail_script "" set teststr "" set exp_teststr "" array set _foreach {} # used in if and while lines set _test_result 0 # clear expect lines list set _el_cont_lines "" # set default session (aka fork) set _el_current_session $_el(fork_current) #fork_id # # Print dots to help user know expect-lite is waiting/sleeping # proc _el_print_dot {_i {reason ""} } { #global _el _var _cond upvar expectlite::_el _el upvar expectlite::INFO INFO upvar expectlite::_el_info_color _el_info_color if {$INFO} { if {$_i == 0 } { #print why if { $reason != "" } { cputs "\n$reason: " $_el_info_color "-nonewline" } } elseif {$_i % 10 == 0 } { cputs "$_i" $_el_info_color "-nonewline" } elseif { $_i % 5 == 0 } { cputs "+" $_el_info_color "-nonewline" } else { cputs "." $_el_info_color "-nonewline" } flush stdout } } #proc _el_print_dot # # Dereference Vars if needed in $_el(line) as read from cmd file # proc _el_deref_line {} { #global _el _var _cond upvar expectlite::_el _el upvar expectlite::_var _var upvar expectlite::_cond _cond if { [regexp {.*\$[A-Za-z0-9_]+.*} $_el(line) ] } { # Detect the use of a user_var #puts "l0>$_el(line)" switch -regexp -- $_el(line) { {^\[[ ]*\$[a-zA-Z0-9_]+[ ]?[=][ a-zA-Z0-9$]+.*} - {^\$.*} - {^\+\$.*} { # repeat variable line, variable line, dyn var line # this is a dyn var definition line - remove leading '+' if { [regexp -line {^\+\$.*} $_el(line)] == 1} { set prepend "+" # remove leading '+' regsub {^\+} $_el(line) {} _el(line) } else {set prepend ""} # this is a var definition line - don't dereference first var (it is being set) set parse_list1 [split $_el(line) "="] #puts "===PL>$parse_list1, [llength $parse_list1]" # check that this is an assignment, and not an increment var command if { [llength $parse_list1] >= 2 } { # check if there are other variables on left side of equals assignment set _left_vars [lindex $parse_list1 0] set _el_var_list [split $_left_vars "$"] #puts "========>$_el_var_list" # is there more than one var on the left-side of the assignment? if { [llength $_el_var_list] > 2 } { set _left_vars [join [lrange $_el_var_list 1 end ] "$"] # dereference left-side vars except first one set _left_vars [parse_var $_left_vars $_var] set _left_vars "\$[lindex $_el_var_list 0]$_left_vars" # detect illegal chars in var name? #regsub {[^A-Za-z0-9_$]} $_left_vars {} _left_vars } # 1st pass of dereferncing assignment variables set _right_value [join [lrange $parse_list1 1 end] "="] #set _el_assignment [parse_var [lindex $parse_list1 1] $_var] #puts "====RV>$_right_value" set _el_assignment [parse_var $_right_value $_var] #set _el_assignment [parse_var $_right_value "$"] # 2nd pass of dereferencing assignment variables set _el(line) "$_left_vars=[parse_var $_el_assignment $_var]" } # place '+' back on front when needed set _el(line) "$prepend$_el(line)" #puts "l2>$_el_assignment|" #puts "l2>$_el(line)" } {^\-\$.*} { # this is a decr var line - don't touch it } {^\*[A-Z]+.*} - {^\=\$.*} { # this is used to dereference a *DIRECTIVE $var line as well as math var line. # this is a math var definition line - don't dereference first var (it is being set) # separate var from rest of line with space regsub {^(=\$[A-Za-z0-9_]+)} $_el(line) {\1 } _el(line) set parse_list1 [split $_el(line) " "] set _math_var [lindex $parse_list1 0] # remove math variable from list set parse_list1 [lreplace $parse_list1 0 0] set _parse_line [ join $parse_list1 " " ] #puts "l2.1>$_parse_line" # first pass at dereferencing variables set _parse_line [parse_var $_parse_line $_var] # extra space " " prevents arrays from being supported set _el(line) "$_math_var [parse_var $_parse_line $_var]" #puts "l2>$_el(line)" } {^\#.*} { # this is a comment line - don't touch it } {^\?.+\?.+} { # This is a conditional line, only dereference Vars in Conditional part # remove "if" if present regsub {^\?[iI]?[fF]?} $_el(line) "?" _el(line) # insert spaces around conditional operator to permit proper resolving of variables # Only act on conditional part of the line (between the ?'s) #regsub {([<>][^^][=]?)} $_el(line) { \1 } _el(line) regsub {\?(.+)([<>][=]?)(.+)\?(.+)} $_el(line) {? \1 \2 \3 ?\4} _el(line) #puts "PL0>$_el(line)" # parse cond from action #set parse_list1 [split $_el(line) "?"] set parse_list1 "" # remove first '?' on conditional line regsub {^[ \t]*[?]} $_el(line) {} _el(line) # parse cond from action lappend parse_list1 [string range $_el(line) 0 [expr [string first $_cond $_el(line)] - 1]] lappend parse_list1 [string range $_el(line) [expr [string first $_cond $_el(line)] + [string length $_cond] ] [string length $_el(line)]] #puts "PL1>$parse_list1|[llength $parse_list1]" if { [llength $parse_list1] >= 2 } { # rebuild _el_line: ?cond?$action_str # build action assigment and else_action without dereferencing set action_str " [join [lrange $parse_list1 1 [llength $parse_list1] ] ""]" # first pass dereferencing set _parse_line [parse_var [lindex $parse_list1 0] $_var ] set _el(line) "?[parse_var $_parse_line $_var]? $action_str" } #puts "EL_LINE_COND>$_el(line)" } default { #puts "EL_LINE1>$_el(line)" # Process Line resolving vars if needed set parse_list1 [split $_el(line) ] #puts "p1>$parse_list1" set plist2 {} foreach i $parse_list1 { lappend plist2 [ parse_var $i $_var ] } set _el(line2) [join $plist2 " "] set _el(line) $_el(line2) # are there still vars to be dereferenced, if so, to a second pass if { [regexp {.*\$[A-Za-z0-9]+.*} $_el(line) ] } { # Process Line resolving vars if needed set parse_list1 [split $_el(line) ] #puts "p1>$parse_list1" set plist2 {} foreach i $parse_list1 { lappend plist2 [ parse_var $i $_var ] } set _el(line2) [join $plist2 " "] set _el(line) $_el(line2) } #puts "EL_LINE2>$_el(line)" } } #switch } #if } #proc _el_deref_line # # Execute expect lines buffered in list variable _el_lines # # proc _el_exec_expect {} { #Allow embedded Expect access to only the following internal vars #global cli_namespace user_namespace timeout remote_host user_dir global errorInfo upvar expectlite::_el_debug_color _el_debug_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::DEBUG DEBUG upvar _el(_el_lines) __el_lines _el_cont_lines __el_cont_lines #puts "=>[llength _el_lines]:$_el_lines:" if { $__el_lines != {} } { # join Expect lines set __el_cont_lines [join $__el_lines " ; "] if {$DEBUG} {cputs "EL-Expect: $__el_cont_lines \n" $_el_debug_color} if {[ catch { uplevel {eval $_el_cont_lines }} error ]} { regsub -all " ; " $__el_cont_lines "\n" __el_cont_lines cputs "ERROR: Expect: \'\n$__el_cont_lines\' \n$errorInfo\n" $_el_err_color } # clear cont lines set __el_lines {} # re-derefence variables in $_el(line) # required when embedded expect changes user_namespace(variable) values _el_deref_line } } # end of _el_exec_expect # idea: if $cmd_file begins with '|' then process as a _el(line) rather than a file # Used for conditional actions, which are a recursive call to _el_script_exec # Also used by interact to execute lines of expect-lite script # initialize vars set _one_line 0 if { $cmd_file == "" } { # use pre-read _el_buf(stack) # read first line of buffer set _el(line) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack] set _el(line_meta) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack 1] } elseif { [ regexp {^\|} $cmd_file ] == 0} { #puts "zzz>$cmd_file|[ regexp {^\|} $cmd_file ]" # read in cmd_file to buffer - no longer used cputs "\nError: Calling el_script_exec has been deprecated\n as of v4.3.0" $_el_err_color #HALT exit 2 } else { # cmd_file is string to evaluate (trim leading spaces if needed) regsub {\|[ ]*(.*)} $cmd_file {\1} _el(line) set _one_line 1 } # set test up for success set _el(success) 1 while { -1 != $_el(line) } { # deref line _el_deref_line # ensure we are in RUN mode set expectlite::_el(STOP) "RUN" #puts "el(line):$_el(line)" switch -regexp -- $_el(line) { ^\# { # Don't send lines that start with a '#' which are commented print_comment_line } {(^>|^>>)\^[A-\]a-z]} { # Don't wait for prompt, Generalized routine to send control chars # get ascii value of char scan [string index $_el(line) [expr [string length $_el(line)] -1]] %c control_char_ascii # parse char from passed string set control_char [string index $_el(line) [expr [string length $_el(line)] -1]] # print timestamp if { $TIMESTAMP } { cputs [ _el_timestamp ] "none" "-nonewline" } # Check if passed char is lower case if {[expr $control_char_ascii - 96] > 0 } { # Send lower case control char send -- [format %c [expr $control_char_ascii - 96]] } else { # Send upper case control char send -- [format %c [expr $control_char_ascii - 64]] } #puts "=>$control_char_ascii" # notify user puts "sending ^$control_char\n" set prev_line $_el(line) } ^\>> { # Don't wait for Prompt just send the line print_comment_line # execute expect lines if present _el_exec_expect # delay to give remote-host a little time (in ms) after 10 # print timestamp if { $TIMESTAMP } { cputs [ _el_timestamp ] "none" "-nonewline" } # Check of remote_host is still connected before sending string if { [catch { send -- "[_el_strip_char $_el(line) $_out_nowait]$_el_eols" } error] } { cputs "CONNECT ERROR: Lost connection to $remote_host \n $error \nExiting..." $_el_err_color # Fail script exit 1 } set prev_line $_el(line) # clear expect buffer expect -re {.*} {} } ^\> { # Wait for Prompt and send the line # do not wait for prompt if only one_line if { $_one_line == 0 } { wait_for_prompt } print_comment_line # execute expect lines if present _el_exec_expect # Set test up for success set _el(success) 1 # print timestamp if { $TIMESTAMP } { cputs [ _el_timestamp ] "none" "-nonewline" } # Check of remote_host is still connected before sending string if { [catch { send -- "[_el_strip_char $_el(line) $_out]$_el_eols" } error] } { puts stderr "CONNECT ERROR: Lost connection to $remote_host \n $error \nExiting..." # Fail script exit 1 } set prev_line $_el(line) # clear expect_out buffer expect -re {.*} {} #set expect_out(buffer) "" if {$connect_method == "none"} { # delay in ms - slow down the host, give the target time to respond after [expr $delay_wait_for_host * 1] } } ^\<\< { # Expect teststr without regex or set success to 0 and fail test '<<'=no regex set _el(success) 0 print_comment_line # execute expect lines if present _el_exec_expect set teststr [_el_strip_char $_el(line) $_in_noregex] # # catch expect, just in case # if {[catch {expect -ex "$teststr" { set _el(success) 1 } } error ] } { # if {$WARN} { # cputs "\nExpect error: Expect-lite: $error\n" $_el_err_color # } # } set _el(exp_timer) 0 # catch expect, just in case if {[catch { expect { -timeout 1 -ex "$teststr" { set _el(success) 1 } timeout { #puts "ZZZ: $_el(exp_timer) $timeout" _el_print_dot $_el(exp_timer) "Waiting" incr _el(exp_timer) # if ^\ has not been preseed if { $_el(STOP) != "STOP" } { # cycle thru expect again, no $exp_teststr found if { $_el(exp_timer) < $timeout } { exp_continue } } }; # timeout }; #end expect } error ] } { if {$WARN} { cputs "\nExpect error: Expect-lite: $error\n" $_el_err_color } } # look at the expect_out(buffer) for debugging if { $DEBUG } { cputs "\nfind<<$teststr>>" $_el_debug_color cputs " in<<$expect_out(buffer)>>" $_el_debug_color #puts " found_in<<$expect_out(0,string)>>" cputs "\n" $_el_debug_color } # show expect found string if { $EXP_INFO && $DEBUG==0 && $_el(success)==1 } { cputs "$el_color(left_angle)$el_color(left_angle)$expect_out(0,string)" $_el_info_color } } ^\< { # Expect teststr or set success to 0 and fail test '<'=use regex set _el(success) 0 print_comment_line # execute expect lines if present _el_exec_expect set teststr [_el_strip_char $_el(line) $_in] # test for single num expect string # if {([string length $teststr]==1) && ([regexp \[0-9\] $teststr])} { # expect { # -re \n$teststr\r { # #puts "\nGood=[_el_strip_char $_el(line) $_in]\n" # set _el(success) 1 # } # -re $teststr { # set _el(success) 1 # } # } # } else { # test for multi-char expect strings set exp_teststr $teststr # new approach for expect, permits breakout with ^\ # calculate timeout set _el(exp_timer) 0 if { [ catch { expect { -timeout 1 -re \n$teststr\r { # special case for single char expects set _el(success) 1 } -timeout 1 -re $exp_teststr { set _el(success) 1 } timeout { #puts "ZZZ: $_el(exp_timer) $timeout" _el_print_dot $_el(exp_timer) "Waiting" incr _el(exp_timer) # if ^\ has not been preseed if { $_el(STOP) != "STOP" } { # cycle thru expect again, no $exp_teststr found if { $_el(exp_timer) < $timeout } { exp_continue } } }; # timeout }; #end expect } error ] != 0 } { if {$WARN} { cputs "\nWarning: $error\n In line: $_el(line)\n" $_el_warn_color } }; #end if catch # finish dots if {$INFO} {puts " \n"} #puts "\nGood=[_el_strip_char $_el(line) $_in]|$_el(success)|$teststr|\n" # } # look at the expect_out(buffer) for debugging if { $DEBUG } { cputs "\nfind<<$teststr>>" $_el_debug_color cputs " in<<$expect_out(buffer)>>" $_el_debug_color #puts " found_in<<$expect_out(0,string)>>" cputs "\n" $_el_debug_color } # show expect found string if { $EXP_INFO && $DEBUG==0 && $_el(success)==1} { regsub ".*($exp_teststr)" $expect_out(buffer) {\1} foundstr cputs "$el_color(left_angle)$foundstr" $_el_info_color } } ^\~< { # Fuzzy Expect teststr with regex or set success to 0 and fail test set _el(success) 0 print_comment_line # execute expect lines if present _el_exec_expect set teststr [_el_strip_char $_el(line) $_in_fuzzy] set testtr_org $teststr # remap escaped parens e.g \( \) set teststr [string map { "\\(" "#{#" "\\)" "#}#" } $teststr ] # use string first to parse set str_first [string range $teststr 0 [expr [string first "(" $teststr] -1 ]] set str_last [string range $teststr [expr [string first ")" $teststr] +1 ] [string length $teststr]] set str_val [string range $teststr [expr [string first "(" $teststr] +1 ] [expr [string first ")" $teststr] -1 ] ] # check str_val is a number if { ([string is integer $str_val ] == 0) && ([string is double $str_val ] ==0) } { set str_val "" } # build teststr #puts "===>$str_first|$str_last|$str_val!" if { ($str_first == $str_last && $str_first == $str_val) || $str_val == "" } { # didn't parse string, show error cputs "\nWarning: Expect-lite unable to parse fuzzy compare number in line:\n$teststr" $_el_warn_color set str_val "" } else { # parsed teststr, continue set teststr "$str_first\(\[0-9.\]+|0x\[0-9a-fA-Fx.\]+\)$str_last" } # restore escaped parens e.g \( \) set teststr [string map { "#{#" "\\(" "#}#" "\\)" } $teststr ] set str_first [string map { "#{#" "\\(" "#}#" "\\)" } $str_first ] #puts "===>$str_first|$str_last|$str_val" #puts "==T=>$teststr" if {$str_val != "" } { #parsing looks OK # catch expect, just in case # if {[catch {expect -re "$teststr" { set _el(success) 1 } } error ] } { # if {$WARN} { # cputs "\nWarning: Expect error: $error\n" $_el_warn_color # } # } set _i 0 if { [ catch { expect { -timeout 1 -re $teststr { set _el(success) 1 } timeout { #puts "FZZ: $_i $timeout" _el_print_dot $_i "Fuzz Waiting" incr _i # if ^\ has not been preseed if { $_el(STOP) != "STOP" } { # cycle thru expect again, no $exp_teststr found if { $_i < $timeout } { exp_continue } } }; # timeout }; #end expect } error ] != 0 } { if {$WARN} { cputs "\nWarning: $error\n In line: $_el(line)\n" $_el_warn_color } }; #end if catch # finish dots if {$INFO} {puts " \n"} } if {$_el(success) == 1 } { #ensure fuzzy comparison is a pass set _el(success) 0 #grab return value from expect line set rtn_val "" set i 1 while { $rtn_val == "" } { if { [catch { set rtn_val $expect_out($i,string) } error] } { # catch error, and set to sane value set rtn_val "endloop" } # clear expect capture buffers if { [ info exists expect_out($i,string)] } { unset expect_out($i,string) } #puts "====>$i|$rtn_val" switch -regexp $rtn_val { {^0x[0-9a-fA-F]+$} { # look for hex value } {^[0-9.]+$} { # value is decimal if { [string length $rtn_val ] > 1 } { set rtn_val [string trimleft $rtn_val "0"] } } "endloop" { # end the loop } default { # continue loop set rtn_val "" } }; #switch incr i } incr i -1 #check fuzz value against global fuzz value if { ([string is integer $rtn_val ] || [string is double $rtn_val ]) && \ ([string is integer $str_val ] || [string is double $str_val ]) } { set fuzz_result 1 if { $rtn_val > [expr $str_val + $_el(fuzz)] } {set fuzz_result 0} if { $rtn_val < [expr $str_val - $_el(fuzz)] } {set fuzz_result 0} #return fuzz comparison set _el(success) $fuzz_result #puts "====f=>$rtn_val|$fuzz_result" } }; # $_el(success) == 1 #set teststr for error message if num is found but out of range if { $str_val != "" } { set teststr "$str_first\($str_val~$_el(fuzz)\)$str_last" } else { set teststr "$str_first\(__NO_NUMBER_FOUND__\)$str_last" } # look at the expect_out(buffer) for debugging if { $DEBUG } { cputs "\nfind<<$teststr>>" $_el_debug_color cputs " in<<$expect_out(buffer)>>" $_el_debug_color #cputs " fuzz_in<<$expect_out($i,string)>>" $_el_debug_color if { [info exists rtn_val] } { if { $rtn_val == "endloop" } { set rtn_val "" } cputs " fuzz_in<<$rtn_val>>" $_el_debug_color } cputs "\n" $_el_debug_color #puts "_el(success) $_el(success)" } # show expect found string if { $EXP_INFO && $DEBUG==0 && $_el(success)==1 } { cputs "~$el_color(left_angle)$expect_out(0,string)" $_el_info_color } } ^\-< { # NOT Expect teststr and If it is found then set success to 0 and fail test set _el(success) 0 print_comment_line # execute expect lines if present _el_exec_expect set teststr [_el_strip_char $_el(line) $_not_in] # delay in ms - slow down the host, give the target time to respond after $delay_wait_for_host # wait for something in expect_out buffer if using localhost if {$connect_method == "none"} { expect { -timeout 1 -notransfer -re {\n.+\n} {} } } # search all text in expect in buffer -- using -notransfer to keep data in expect input buffer # Reverse logic, if the NOT match string is found, then set _el(success) to 0 and fail test expect { -timeout 0 -notransfer -re $teststr {set _el(success) 0} default {set _el(success) 1} } # look at the expect_out(buffer) for debugging if { $DEBUG } { cputs "\nNOT find<<$teststr>>" $_el_debug_color cputs " in>>$expect_out(buffer)<<" $_el_debug_color cputs "\n" $_el_debug_color } } {^~=[ ]?[0-9.]+} { # Update the fuzzy expect value (or range) # validate that the timeout value is a number print_comment_line # execute expect lines if present _el_exec_expect set fuzzy_int [_el_strip_char $_el(line) "~=" ] #trim extra white space set fuzzy_int [string trimright $fuzzy_int ] if {[regexp \[^0-9.\ \]+ $fuzzy_int]} { if {$WARN} { cputs "WARN: Bad Fuzzy Value: [_el_strip_char $_el(line) "~=" ] " $_el_warn_color } } else { set fuzz_line "\nSetting Fuzzy Expect to: + or - $fuzzy_int \n" set _el(fuzz) $fuzzy_int } # print new timeout value if one_line is set (e.g. from IDE) if {$INFO} { cputs $fuzz_line $_el_info_color } } ^\@ { # Update the timeout value # validate that the timeout value is a number print_comment_line # execute expect lines if present _el_exec_expect if {([regexp \[^0-9\ \]+ [_el_strip_char $_el(line) $_timeout]])} { if {$WARN} { cputs "WARN: Bad Timeout Value: [_el_strip_char $_el(line) $_timeout] " $_el_warn_color } #send "quit$_el_eols" # Stop the script Now! - removed in 4.4.0 #exit 1 } else { #puts "\nSetting Expect Timeout to: [_el_strip_char $_el(line) $_timeout] \n" set timeout_int [_el_strip_char $_el(line) $_timeout] if { $cli_namespace($timeout_multiplier) != 1 } { # user has changed timeout_multiplier to something other than 1, use the value set timeout [expr $timeout_int * $cli_namespace($timeout_multiplier)] set timeout_line "\nTimeout Multiplier mode: Setting Expect Timeout to: $timeout \n" } else { set t_timeout $timeout_int set timeout_line "\nSetting Expect Timeout to: $t_timeout \n" set timeout $t_timeout } } # print new timeout value if one_line is set (e.g. from IDE) if { $_one_line == 1 } { if {$INFO} { cputs $timeout_line $_el_info_color } } } ^\\\?[iI]?[fF]? { # Conditional processing - ?cond?action::else_action # execute expect lines if present _el_exec_expect print_comment_line set _cond_line [_el_strip_char $_el(line) $_cond_regex] #puts "\n##>[_el_strip_char $_el(line) $_cond_regex]\n" # remove optional 'if' or 'IF' regsub {^[iI]?[fF]?} $_cond_line "" _cond_line #parse conditional and action (and else_action if needed) set _else_action "" set _action [string range $_cond_line [expr [string first $_cond $_cond_line] + [string length $_cond] ] [string length $_cond_line]] #puts "\n##ACT>$_cond_line|$_action|[string first $_cond $_cond_line]|[string length $_cond]|[string length $_cond_line]" # check for else action - defined by :: if { [regexp $_cond_else $_action] } { # add spaces to else separator regsub {([^0-9a-f])::([^0-9a-f])} $_action "\\1 $_cond_else \\2" _action #regsub {::} $_action " $_cond_else " _action # parse action into action::else_action #set _else_action [string range $_action [expr [string first $_cond_else $_action] + [string length $_cond_else] ] [string length $_action]] #set _action [string range $_action 0 [expr [string first $_cond_else $_action] - [string length $_cond_else] ]] regsub {^(.+) :: (.+)$} $_action "\\2" _else_action regsub {^(.+) :: (.+)$} $_action "\\1" _action # trim trailing spaces set _action [string trimright $_action] #puts "#2#>then$_action|else$_else_action|" } set _conditional [string range $_cond_line 0 [expr [string first $_cond $_cond_line] - [string length $_cond] ]] # define list of supported conditional operators set _cond_oper_list { == != <= >= < > } # find conditional operator set _cond_oper "@" foreach k $_cond_oper_list { if { [regexp $k $_conditional] } { set _cond_oper $k break } } # parse around conditional operator set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]] set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]] #puts "\n#@@|$_cond_oper|$_conditional|$_cond_arg1|$_cond_arg2|" # remove leading and trailing spaces from conditional arguments # count the number of non-space chars in condition if {[string length [regexp -inline {[^ ]+} $_cond_arg1]] > 1 } { # condition larger then 1 byte regsub -all {([ ]*)([^ ].*[^ ])([ ]*)} $_cond_arg1 {\2} _cond_arg1 } else { # condition only 1 byte in size regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1 } if { [string length [regexp -inline {[^ ]+} $_cond_arg2]] > 1 } { # condition larger then 1 byte regsub -all {([ ]*)([^ ].*[^ ])([ ]*)} $_cond_arg2 {\2} _cond_arg2 #puts ">$_cond_arg2<" } else { # condition only 1 byte in size regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2 #puts ">$_cond_arg2<" } # preserve buffer pointer - if not one_line if { $_one_line != 1 } { set _tmp_buf_ptr $_el_buf($buf_stack,ptr) } # validate comparison and if true, send to _el_script_exec (recursive call) # check for unresolved Var # Var is defined as in the set [a-zA-Z0-9_] if { [regexp {\$[a-zA-Z0-9_]+} $_conditional] } { if {$DEBUG} { cputs "EL:Unresolved Var:$_conditional" $_el_debug_color} # replace all unresolved vars with "" regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg1 {} _cond_arg1 regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg2 {} _cond_arg2 } # build test line set _test " expr { \"$_cond_arg1\" $_cond_oper \"$_cond_arg2\" } " # check for syntax errors and evaluate result of test line if {[catch { eval $_test } error ] } { if {$WARN} { cputs "\nWarning: Expect-lite: $error: Unable to detect conditional operator\n" $_el_warn_color cputs " Evaluating line:$_test|$_action|$_else_action" $_el_warn_color } } else { # Show user the if statement, action and result set _test_result [eval $_test ] if {$_test_result} { set _test_result "TRUE" # code block, else_action is false if { [ regexp {^[ \t]*\[} $_else_action ] } { #puts "=====going to>$_el(line_meta)|$_el_buf(stack)" _el_buffer_goto [expr $_el(line_meta) ] $_el_buf(stack) } } else { set _test_result "FALSE" # code block, action is false if { [ regexp {^[ \t]*\[} $_action ] || [ regexp {\?.+\?.*\[} $_action ] } { #puts "=====going to>$_action|$_el(line_meta)|$_el_buf(stack)" _el_buffer_goto [expr $_el(line_meta) ] $_el_buf(stack) } } if {$INFO} { if { $_else_action == ""} { cputs "\nIf:$_test|then$_action|result=$_test_result\n" $_el_info_color #puts "======buf stack>$_el_buf(stack)" } else { cputs "\nIf:$_test|then$_action|else$_else_action|result=$_test_result\n" $_el_info_color } };#if INFO # issue warning if both then & else actions are code blocks if { [regexp {^[ \t]*\[} $_action ] && [regexp {^[ \t]*\[} $_else_action ] } { if { $WARN } { cputs "\nWarning: Expect-lite: Code Blocks not supported in both then & else actions\n" $_el_warn_color } } # no syntax error, go ahead and eval the conditional action or else action # skip to label if present in action or else_action if { [eval $_test ] } { # remove any leading space and trailing from action regsub {^[ \t]+} $_action {} _action regsub {[ \t]+$} $_action {} _action # Is there a jump to a label in action? if { [ regexp "^$_label" $_action ] } { _el_buffer_goto [_el_buffer_search $_el_buf($buf_stack,ptr) $_action $buf_stack] $_el_buf(stack) } elseif { [ regexp {^\[} $_action ] } { # code block NOP } else { # Interpret action with recursive call to _el_script_exec _el_script_exec "\|$_action" $buf_stack } } elseif { $_else_action != "" } { # remove any leading and trailing space from else_action regsub {^[ \t]+} $_else_action {} _else_action regsub {[ \t]+$} $_else_action {} _else_action # Is there a jump to a label in else_action? if { [ regexp "^$_label" $_else_action ] } { _el_buffer_goto [_el_buffer_search $_el_buf($buf_stack,ptr) $_else_action $buf_stack] $_el_buf(stack) } elseif { [ regexp {^\[} $_else_action ] } { # code block NOP } else { # Interpret else_action with recursive call to _el_script_exec _el_script_exec "\|$_else_action" $buf_stack } } } if { $_one_line != 1 } { # label not found if { $_el_buf($buf_stack,ptr) == -1 } { # label search failed (-1), restore buf_ptr, allow script to continue #set _el_buf($buf_stack,ptr) $_tmp_buf_ptr _el_buffer_goto $_tmp_buf_ptr $_el_buf(stack) } # infinite loop detected! if { $_el_buf($buf_stack,ptr) == -2 } { # label search failed (-2), restore buf_ptr, allow script to continue #set _el_buf($buf_stack,ptr) $_tmp_buf_ptr _el_buffer_goto $_tmp_buf_ptr $_el_buf(stack) # signal to fail script - something is wrong set _el(success) 0 # tell the user why this failed set prev_line "Infinite Loop Detected!" } #puts "++++++ptr>$_el_buf($buf_stack,ptr)" } } ^\;;[^;] { # Send "comment" to stdout unbuffered # execute expect lines if present _el_exec_expect # Find color at beginning of comment line and use it, if not, use default comment color set unbuf_comment [_el_strip_char $_el(line) $_stdout_comment_nobuf] set unbuf_color [find_color $unbuf_comment] if { $unbuf_color != "" } { # remove first word regsub "$unbuf_color" $unbuf_comment "" unbuf_comment # use custom color cputs $unbuf_comment $unbuf_color } else { # use default comment color cputs $unbuf_comment $_el_comment_color } } ^\;[^;] { # Send "comment" to stdout buffered # execute expect lines if present _el_exec_expect print_comment_line set comment_line [_el_strip_char $_el(line) $_stdout_comment] # print comment if one_line is set if {$_one_line} { print_comment_line } } ^\~[^=<] { # include file from same location at cmd_file # Uses recursion to interpret included file # execute expect lines if present _el_exec_expect print_comment_line set _include_file [_el_strip_char $_el(line) $_include] #puts "==========> $_include_file" # set up passed values set _var_value [split $_include_file " "] set _include_file_str $_include_file # get only the first word as include file set _include_file [lindex [split $_include_file " " ] 0] # This was 4.1 EL_LIBRARY behavior if { $NOINCLUDE == 0 } { # don't include file if name is set to __NO_STRING_CAPTURED__ (which is a blank dynamic/capture variable) if { $_include_file != "__NO_STRING_CAPTURED__" } { # normalize file name to read to allow tilde expansion e.g. ~fred/file.inc #puts "======>[ catch { file normalize $_include_file } error ]|$error" if { [catch { file normalize $_include_file } error ] == 0 } { set _include_file [file normalize $_include_file ] } else { if {$WARN} { cputs "\nWarning: $error\n" $_el_warn_color } } # absolute path to include file? set _slash "/" if { [string index $_include_file 0] == $_slash} { set include_path_file "$_include_file" } else { set include_path_file "[parse_cmd_file_path $_el(cmd_file)]$_include_file" } #puts "->$include_path_file" # preserve include file name for future reference set _el(include_file_name) $_include_file if {$INFO} { cputs "\nIncluding: $_include_file_str\n" $_el_info_color } # Make Recursive Call in stand alone mode # parse passed constants on include line set _pass_var_values [ _el_parse_var_value $_var_value ] #puts "==========> $_pass_var_values" # preserve constants going into include set _keep_var_values [ _el_preserve_const $_pass_var_values ] # read in cmd_file to buffer set buf_stack [_el_buffer $include_path_file] # preserve test_failed going into include file set _preserve_test_result $_el(test_failed) set _el(test_failed) 0 set result [_el_script_exec "" $buf_stack] # don't report false include failure, set test_failed switch -- $result { 0 { # pass set _el(success) 1 set _el(test_failed) $_preserve_test_result } 1 { # fail set _el(success) 0 # no need to restore, it failed set _el(test_failed) 1 cputs "\n##Include Result: FAILED: $include_path_file\n" $_el_err_color } 2 { # fail right now! # return result code to caller, stop now return $result } }; #switch # pop _el_buf(stack) _el_buffer_stack_clear $buf_stack incr buf_stack -1 # sync with global value, for INTERACT/IDE set _el_buf(stack) $buf_stack # restore constants _el_restore_const $_keep_var_values # clear include file name for future reference set _el(include_file_name) "" }; # if include file not __NO_STRING_CAPTURED__ } else { cputs "\nWarning: *NOINCLUDE: Skipping include file:$_include_file\n" $_el_warn_color }; #if } ^\\+\\$[A-Za-z0-9_]+[=] { # Setup Dynamic Var using Expect Capture # execute expect lines if present _el_exec_expect print_comment_line # delay in ms - slow down the host, give the target time to respond after $delay_wait_for_host # parse $_el(line) to pull out var and expect parts #puts "\n->$_el(line)" set user_var [string range $_el(line) 1 [expr [string first "=" $_el(line)] -1 ]] set user_value [string range $_el(line) [expr [string first "=" $_el(line)] +1 ] [string length $_el(line)]] #puts "\n->$user_var=$user_value" # remove '$' in front of the Var regsub {\$} $user_var "" user_var # Require dynamic variable to capture with a prompt? if { $DVARPROMPT } { set _expect_str "\n$_el(prompt)|\n.*\\\$ $|\n.*# $|\n.*> $|\n.*% $" } else { # no prompt required for dynamic variable capture set _expect_str ".*$user_value" } set capture_val "__NO_STRING_CAPTURED__" set _el(var_capture_begin) [ clock seconds ] expect { -notransfer -re "$_expect_str" { # Do capture in expect buffer if { [catch {regexp -line "$user_value" $expect_out(buffer) match_val capture_val}] } { set capture_val "__NO_STRING_CAPTURED__" set match_val "" } # remove newlines from capture value # add spaces to make foreach lists easier regsub -all {[\n\r]+} $capture_val " " capture_val }; #notransfer # expect should never timeout, but just in case timeout { set _el(var_capture_end) [ clock seconds ] set _el(var_capture_duration) [ expr $_el(var_capture_end) - $_el(var_capture_begin)] if { $timeout != $_el(var_capture_duration)} { puts "BUG: Expect-lite: Var Capture Timed Out!\n" puts "Debugging Info: \n\tEL_Line:$_el(line)\n\texpect timeout=$timeout secs \n\tDuration of capture:$_el(var_capture_duration) secs \n\n" show_vars } else { if {$WARN} { if {$DVARPROMPT} { cputs "Warning: Expect-lite: Var Capture Timed Out! Recommend lengthening timeout, current timeout is: $timeout secs\n" $_el_warn_color } else { cputs "Warning: Expect-lite: *NODVPROMPT: Var Capture Timed Out! $user_value not found.\n" $_el_warn_color } } if { $DEBUG } { cputs "\nfound<<$capture_val>>" $_el_debug_color cputs "\nin<<$expect_out(buffer)>>" $_el_debug_color } } }; #timeout }; #expect if { $INFO } { #puts "\nAssigned Var:$user_var=|$capture_val|\n" cputs "\nAssigned Var:$user_var=$capture_val\n" $_el_info_color } if { $DEBUG } { cputs "\nvar_found<<$capture_val>>" $_el_debug_color cputs "\nvar_in<<$expect_out(buffer)>>" $_el_debug_color } # set var (similar to below) set user_namespace($user_var) $capture_val } {^\$[A-Za-z0-9_]+[=]([ ]?|[~\$\[/A-Za-z0-9_.-]+)} { # allow a single space or blank as a value in addition to the normal assignment # execute expect lines if present _el_exec_expect # Set a user variable set user_var [string range $_el(line) 1 [expr [string first "=" $_el(line)] -1 ]] set user_value [string range $_el(line) [expr [string first "=" $_el(line)] +1 ] [string length $_el(line)]] # remove '$' in front of the Var regsub {\$} $user_var "" user_var # Assign the Var if { [string len $user_value ] > 0 } { # set single space to blank var #if { $user_value == " " } { set user_value "" } set user_namespace($user_var) $user_value } else { # empty value, unset var, make available as a shell var catch { unset user_namespace($user_var) } } # Used for debugging #puts "->$user_var|$user_value|" #parray user_namespace } ^\\+\\$[A-Za-z0-9_]+ { # increment Var, decimal # execute expect lines if present _el_exec_expect print_comment_line set _tmp_var [_el_strip_char $_el(line) $_incr_var] #remove traling space regsub {[ \t]+$} $_tmp_var {} _tmp_var #increment decimal number if possible catch { incr user_namespace($_tmp_var)} # else, pass string value back without incrementing } ^\-\\$[A-Za-z0-9_]+ { # decrement Var # execute expect lines if present _el_exec_expect print_comment_line set _tmp_var [_el_strip_char $_el(line) $_decr_var] #remove traling space regsub {[ \t]+$} $_tmp_var {} _tmp_var # decrement variable catch { incr user_namespace($_tmp_var) -1 } #puts "->$_el(line) $_decr_var $_tmp_var" } {^=\$[A-Za-z0-9_]+} { # math variable # execute expect lines if present _el_exec_expect print_comment_line # strip math_var symbol from beginning of line regsub {^=\$} $_el(line) "" _tmp_var # normalize spaces regsub -all {[ ]+} $_tmp_var " " _tmp_var set _el_parse_list [split $_tmp_var " "] set var [lindex $_el_parse_list 0] # remove $var from list set _el_parse_list [lreplace $_el_parse_list 0 0] set _el_predicate [join $_el_parse_list " "] # check if math variable exists if { [info exists user_namespace($var)] == 0 } { # if not, set to blank set user_namespace($var) 0 } if { [string length $user_namespace($var)] > 0 && ( [string is integer $user_namespace($var) ] || [string is double $user_namespace($var) ] ) } { #$var is a number # supports oper: << >> & | ^ + = * / % pow(x,y) if { [catch { set user_namespace($var) [expr $user_namespace($var)$_el_predicate] } error]} { if {$WARN} { cputs "\nWarning: Expect-lite: Unable to interpret $_el(line) \n $error" $_el_warn_color } } } else { #$var is a string # get operator. % + / ; // ;; - regsub {([%+/;-]|[/;][/;]).*} $_el_predicate {\1} _operator #puts "===strmath==>$_operator#$_el_parse_list#" set show_error 0 switch -re $_operator { "%" { # slice/ordinal e.g. % 5-9 # pop operator off front set _el_parse_list [lreplace $_el_parse_list 0 0] set _el_predicate [join $_el_parse_list " "] set _el_parse_list [split $_el_predicate "-"] foreach {start end} $_el_parse_list {break} #puts "===strmath1==>$start#$end#$_el_parse_list" # decrement range to zero-base catch {incr start -1; incr end -1} if { [catch { set user_namespace($var) [string range $user_namespace($var) $start $end] } error]} { set show_error 1 } } {[+]} { # concat e.g. + string # pop operator off front if { [llength $_el_parse_list ] > 1 } { set _el_parse_list [lreplace $_el_parse_list 0 0] } else { set _el_parse_list [string trimleft $_el_parse_list "+"] } #puts "===strmath2==>$_el_parse_list#" if { [catch { set user_namespace($var) "$user_namespace($var)$_el_parse_list" } error]} { set show_error 2 } } {^[/;][/;]} { # search/replace - no regex # determine parsing char regsub {([/;]).*} $_operator {\1} splitchar set replacelist [ split $_el_predicate "$splitchar" ] #puts "===strmath3==>$replacelist#$_el_predicate#" # resulting list is: null search replace null # remove nulls in list regsub -all "{}" $replacelist "" replacelist #regsub -all $search $user_namespace($var) $replace user_namespace($var) if { [catch { set user_namespace($var) [string map $replacelist $user_namespace($var) ]} error]} { set show_error 3 } } {^[;/]} { # regex search/replace # determine parsing char regsub {([/;]).*} $_operator {\1} splitchar set replacelist [ split $_el_predicate "$splitchar" ] #puts "===strmath4==>$replacelist#$_el_predicate#" # resulting list is: null search replace null # remove nulls in list regsub -all "{}" $replacelist "" replacelist foreach {search replace} $replacelist {break} #regsub -all $search $user_namespace($var) $replace user_namespace($var) if { [catch { regsub -all -- $search $user_namespace($var) $replace user_namespace($var)} error]} { set show_error 4 } #regsub -all $search $user_namespace($var) $replace user_namespace($var) } {[-]} { # subtract or remove e.g. - string # remove leading white space regsub {([-])[ ]+(.+)} $_el_parse_list {\1\2} _el_parse_list #reparse parse_list set _el_predicate [join $_el_parse_list " "] set _el_parse_list [split $_el_predicate "-"] # pop operator off front set _el_parse_list [lreplace $_el_parse_list 0 0] # create replace_map set replacelist [list $_el_parse_list {} ] #puts "===strmath5==>$_el_predicate#$_el_parse_list#" if { [catch { set user_namespace($var) [string map $replacelist $user_namespace($var) ]} error]} { set show_error 5 } } default { set show_error 9 } }; #swicth if { $show_error } { if {$DEBUG} { cputs "\nWarning:$show_error Expect-lite: Unable to interpret $_el(line) \n $error" $_el_debug_color } elseif {$WARN} { cputs "\nWarning:$show_error Expect-lite: Unable to interpret $_el(line)" $_el_warn_color } } }; #else } ^\! { # Run an Embedded Expect Line(s) (limited support) # don't add Expect comment lines (hint they start with '!#' if { [regexp -line {^![ \t]*#} $_el(line) ] == 0 } { # add Expect Lines to _el(_el_lines) list lappend _el(_el_lines) [_el_strip_char $_el(line) $_exec] #puts "+>[llength $_el(_el_lines)]:$_el(_el_lines):" } } ^\:[0-9.] { # sleep function - part of v4.9.0 # prints row of dots to help user know script is sleeping print_comment_line # execute expect lines if present _el_exec_expect # validate that the sleep value is a number if {[string is double [_el_strip_char $_el(line) $_sleepchar]] == 0} { if {$WARN} { cputs "WARN: Bad Sleep Value: [_el_strip_char $_el(line) $_sleepchar] " $_el_warn_color } } else { set sleep_int [_el_strip_char $_el(line) $_sleepchar] if {$INFO} { cputs "\nSleeping: $sleep_int " $_el_info_color } #handle miliseconds set sleep_milisec [expr int($sleep_int * 1000) % int(1000)] #puts "=>$sleep_milisec" set _i 1 while {$_i <= $sleep_int} { _el_print_dot $_i incr _i if {$_i <= $sleep_int} {sleep 1} } #milisecond sleep if {$sleep_milisec > 0} { after $sleep_milisec} if {$INFO} {puts " \n"} }; #end if } ^\\*~ { # include file of failure script - called when test fails # Uses recursion to interpret included file # expect-lite directive # execute expect lines if present _el_exec_expect print_comment_line if { $_one_line == 0 } { set _el_fail_script [_el_strip_char $_el(line) $_include_fail] } else { # we are inside a recursive call uplevel {set _el_fail_script [_el_strip_char $_el(line) $_include_fail]} } # don't include file if name is set to __NO_STRING_CAPTURED__ (which is a blank dynamic/capture variable) if { $_el_fail_script == "__NO_STRING_CAPTURED__" } { # don't set fail_script set _el_fail_script "" } if { $_one_line == 0 } { if {$INFO} { cputs "\nFail Include Script: $_el_fail_script\n" $_el_info_color } } else { # we are inside a recursive call if {$INFO} { uplevel {cputs "\nFail Include Script: $_el_fail_script\n" $_el_info_color} } } # update global fail_script value (for SHOW ENV) set _el(fail_script) $_el_fail_script } ^\\*/.*/$ { # Set a user defined prompt # expect-lite directive # execute expect lines if present _el_exec_expect # strip leading and trailing slashes regsub {^\*/} $_el(line) {} el_u_prompt regsub {/$} $el_u_prompt {} _el(prompt) # Set empty prompt to something sane, the default prompt if { $_el(prompt) == "" } { set _el(prompt) $_el(default_prompt) } if $INFO { if { $_el(prompt) == $_el(default_prompt) } { cputs "INFO: User Defined Prompt is now default: $_el(prompt)" $_el_info_color } else { cputs "INFO: User Defined Prompt: $_el(prompt)" $_el_info_color } } } ^\\*[a-zA-Z] { # Process expect-lite run-time directives # expect-lite directives print_comment_line # execute expect lines if present _el_exec_expect print_comment_line # trim off white space set _el(line) [string trimright $_el(line)] # remove any multiple spaces regsub -all {[ ]+} $_el(line) " " _el(line) # Process the directive - return 0 to fail set _el(success) [_el_global_directive $_el(line)] } ^\\\[ { # start block of lines # execute expect lines if present _el_exec_expect print_comment_line set _cond_line [string trimleft $_el(line) '\['] #puts "====>start block lines|$_cond_line|$_el(line_meta)" set _conditional [string trimright $_cond_line] if { [regexp {^\[[ ]*\$[a-zA-Z0-9_]+[ ]?[=]} $_el(line)] } { ### foreach loop set _cond_oper "=" # parse around conditional operator set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]] set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]] # clean up white space regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1 #regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2 set user_var $_cond_arg1 # remove '$' in front of the Var regsub {\$} $user_var "" user_var # create foreach list set line_meta $_el(line_meta) if { [info exists _foreach($line_meta,$user_var)] == 0 } { # clean up white space regsub -all {[ ]+} $_cond_arg2 " " _cond_arg2 set _cond_arg2 [string trimleft $_cond_arg2 ] set _cond_arg2 [string trimright $_cond_arg2 ] set _foreach_list [split $_cond_arg2] if {$INFO} { cputs "\nForeach: $_cond_arg1=$_cond_arg2" $_el_info_color };#if INFO # add extra item to allow last user item to be executed lappend _foreach_list "END" } else { # restore list - hashed based on meta line and var name set _foreach_list $_foreach($line_meta,$user_var) } # set value from first item in foreach list set user_value [lindex $_foreach_list 0] #puts "====>repeat lines|$_foreach_list|[llength $_foreach_list]|$user_var|$user_value" # delete first item in list set _foreach_list [ lreplace $_foreach_list 0 0] # is list empty, then stop loop if { [llength $_foreach_list] == 0 } { set _foreach_list "" # clear foreach info, to allow re-run of this foreach loop unset -nocomplain _foreach($line_meta,$user_var) if { $_el(line_meta) != -1 } { # stop loop, jump to bottom of loop + 1 _el_buffer_goto [expr $_el(line_meta) + 0] $_el_buf(stack) } } else { #List not empty, Loop back # save list info set _foreach($line_meta,$user_var) $_foreach_list # Assign the Var set user_namespace($user_var) $user_value if {$INFO} { cputs "\nForeach: \$$user_var=$user_value\n" $_el_info_color };#if INFO } } else { ### While Loop # define list of supported conditional operators set _cond_oper_list { == != <= >= < > } # find conditional operator set _cond_oper "@" foreach k $_cond_oper_list { if { [regexp $k $_conditional] } { set _cond_oper $k break } } # parse around conditional operator set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]] set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]] # clean up white space regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1 regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2 #puts "\n#@@|$_cond_oper|$_conditional|$_cond_arg1|$_cond_arg2|" # Var is defined as in the set [a-zA-Z0-9_] if { [regexp {\$[a-zA-Z0-9_]+} $_conditional] } { if {$DEBUG} { cputs "EL:Unresolved Var:$_conditional" $_el_debug_color} # replace all unresolved vars with "" regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg1 {} _cond_arg1 regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg2 {} _cond_arg2 } # build test line - allow blank arguements set _test " expr { \"$_cond_arg1\" $_cond_oper \"$_cond_arg2\" } " # Do not allow blanks in greater/lesser than comparisons if { [lsearch { <= >= < > } $_cond_oper ] != -1 } { # build test line if { $_cond_arg1 == "" || $_cond_arg2 == "" } { # something is wrong, one of the conditions is blank, break loop set _test " expr { $_cond_arg1 $_cond_oper $_cond_arg2 } " } } # check for syntax errors and evaluate result of test line if {[catch { eval $_test } error ] } { if {$WARN} { cputs "\nWarning: Expect-lite: $error: \nWhile Loop: One of comparison values is blank" $_el_warn_color cputs " Evaluating line:$_test" $_el_warn_color } #skip block lines, don't jump if bad line-meta value if { $_el(line_meta) != -1 } { #set _el_buf($buf_stack,ptr) [expr $_el(line_meta) + 1] _el_buffer_goto [expr $_el(line_meta) + 1] $_el_buf(stack) } } else { # Show user the while statement, action and result set _test_result [eval $_test ] if {$_test_result} { set _test_result "TRUE" } else { set _test_result "FALSE" } if {$INFO} { cputs "\nWhile:$_test|result=$_test_result\n" $_el_info_color };#if INFO # no syntax error, go ahead and eval the conditional action or else action # skip to label if present in action or else_action if { [eval $_test ] } { # continue loop # test for infinite loop set retcode [_el_check_infinite_loop] if { $retcode == -2 } { # infinite loop failed (-2) # signal to fail script - something is wrong set _el(success) 0 # tell the user why this failed set prev_line "Infinite Loop Detected!" set _test_result -2 } } elseif { $_el(line_meta) != -1 } { # stop loop, jump to bottom of loop + 1 _el_buffer_goto [expr $_el(line_meta)] $_el_buf(stack) } };#if Catch }; #else While loop } ^\\\] { # end block of lines # execute expect lines if present _el_exec_expect print_comment_line #puts "====>end block lines|$_el(line_meta)" if { $_one_line == 0 } { # jump back to top of block lines _el_buffer_goto [expr $_el(line_meta) - 1 ] $_el_buf(stack) } } default { # blank lines are allowed } }; #end switch #puts "line_ptr->$_el_buf($buf_stack,ptr)|$_el(success)" # Fail the test if Expect fails or Expect Fuzzy fails if {$_el(success) != 1 && [regexp "^$_in|$_in_fuzzy" $_el(line)]==1 } { cputs "\n\n FAILED COMMAND:[_el_strip_char $prev_line $_out] \n" $_el_err_color cputs " Expect Failed:$teststr\n" $_el_err_color if { $_el_current_session != "default" } { cputs " Current Fork Session: $_el_current_session \n\n" $_el_err_color } } # Fail the test if NOT Expect fails if {$_el(success) != 1 && [regexp "^$_not_in" $_el(line)]==1 } { cputs "\n\n FAILED COMMAND:[_el_strip_char $prev_line $_out] \n" $_el_err_color cputs " Expect Found:$teststr\n\n" $_el_err_color if { $_el_current_session != "default" } { cputs " Current Fork Session: $_el_current_session \n\n" $_el_err_color } } # Fail the test, and invoke Fail_script if {$_el(success) != 1 } { if { $_el_fail_script != "" } { # run fail script to clean up # absolute path to fail include file? set _slash "/" if { [string index $_el_fail_script 0] == $_slash} { set include_path_file "$_el_fail_script" } else { set include_path_file "[parse_cmd_file_path $_el(cmd_file)]$_el_fail_script" } #puts "->$include_path_file" if {$INFO} { cputs "\nIncluding Fail Script: $_el_fail_script\n" $_el_info_color } # set fail_script up for success set _el(success) 1 # Make Recursive Call # read in cmd_file (fail script) to buffer set buf_stack [_el_buffer $include_path_file] _el_script_exec "" $buf_stack # pop _el_buf(stack) _el_buffer_stack_clear $buf_stack incr buf_stack -1 # sync with global value, for INTERACT/IDE set _el_buf(stack) $buf_stack # special short cut to allow main script to continue if { [info exists _el(continue)] == 1 } { if { $_el(continue) == 1 } { set _el(success) 1 } set _el(continue) 0 } else { # no backdoor to continue script, fail script set _el(success) 0 } #puts "success->$_el(success)" #puts "FS>$_el_fail_script" } # last chance to let script continue, even though it should fail if {$NOFAIL} { set _el(success) 1 set _el(test_failed) 1 } if { $_el(success) != 1 } { # allow fail script to set success, and continue if need be #protected_send "quit$_el_eols" #exit 1 # FATAL return 2 } } # ensure we stop at end of file/buffer if { $_one_line == 0 } { if { $_el_buf($buf_stack,ptr) >= [llength $_el_buf($buf_stack)] } { # exit the while loop set _el(line) -1 } if {$_el_buf($buf_stack,ptr) < 0 } { # last chance to return unknown return -1 } } # Get next line in buffer # Or return if in one_line mode if { $_one_line == 0 } { # not in one line, normal processing # read next line from buffer incr _el_buf($buf_stack,ptr) set _el(line) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack] # read meta-data for line set _el(line_meta) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack 1] # remove leading white space on line (permitting indentation) regsub {^[ \t]+} $_el(line) {} _el(line) } else { # one_line is true (which means invoked by a conditional) # or invoked from IDE # Done processing one line, and handling failures # so just return from this recursive call switch -regex -- $_test_result { "TRUE" { return 1 } "FALSE" { return 0 } [-0-9]+ { return $_test_result } default { return "test_result_error" } } }; #endif not one_line }; #end while # print last comment line print_comment_line # set result code if { $_el(test_failed) == 1} { # FAIL return 1 } else { # PASS return 0 } } # end of _el_script_exec # ############# MAIN ###################### # # Main Program starts here # # proc main { } { upvar expectlite::connect_method connect_method upvar expectlite::remote_host remote_host upvar expectlite::_el_info_color _el_info_color upvar expectlite::_el_warn_color _el_warn_color upvar expectlite::_el_err_color _el_err_color upvar expectlite::delay_wait_for_host delay_wait_for_host upvar expectlite::WARN WARN upvar expectlite::INFO INFO upvar expectlite::_el_eols _el_eols upvar expectlite::_el _el upvar expectlite::DEBUG_LOG DEBUG_LOG upvar expectlite::cmd_file cmd_file _el_init_globals # check terminal type for use of colors check_term_type _el_read_args $::argc $::argv # Check Expect Version, warn if old # if { [exp_version] < "5.42.0" } { # puts "Warning: older version of expect\n" # } if [catch { exp_version 5.42.0 } msg ] { cputs "\nWarning: $msg\n" $_el_err_color } # read in cmd file and return handle to buffer set cmd_file_ptr [ read_cmd_file ] # Use selected (at top of file) connect_method switch $connect_method { telnet {connect_telnet_host $remote_host } ssh {connect_ssh_host $remote_host } ssh_key {connect_ssh_key_host $remote_host } none {_el_connect_localhost $remote_host } } # initialize remote_host_init, fork session session_init $cmd_file_ptr #if { $DEBUG_LOG==1 } { log_file -noappend debug_output.txt } - removed in v4.4.0 # Send commands to remote host, and validate response set _el_result [ _el_script_exec "" $cmd_file_ptr ] after [expr 5 * $delay_wait_for_host] #To show the very end of the test, wait for that very last prompt # clear expect buffer expect -re {.*} {} # exit local or remote shell if { [catch { send "exit $_el_eols" } error] } { if {$WARN} {cputs "Warning: Lost connection to $remote_host \n $error\n $errorInfo " $_el_warn_color} } wait_for_prompt # Print result of test switch -- $_el_result { 0 { # PASS if {$INFO} {cputs "\n\n##Overall Result: PASS \n\n" $_el_info_color } } 1 { # FAIL if {$INFO} {cputs "\n\n##Overall Result: FAILED (*NOFAIL on)\n\n" $_el_err_color } exit 1 } 2 { # FATAL if {$INFO} {cputs "\n\n##Overall Result: FAILED \n\n" $_el_err_color } exit 1 } -1 { # UNKNOWN if {$INFO} {cputs "\n\n##Overall Result: UNKNOWN \n\n" $_el_err_color } exit 1 } } #if { $DEBUG_LOG==1 } { log_file } # exit with 0 to indicate that test passed exit 0 } }; #end namespace expect-lite # run the main program (in standalone) when run with expect #if { [info exist ::EL_LIBRARY] != 1} { main } if { [string match "*expect*" [info nameofexecutable]] } { expectlite::main } expect-lite.proj/README0000644000076400007640000001054712564335303015371 0ustar cvmillercvmiller expect-Lite Automation for the rest of us Installation and Quick Start Guide ------------------------------------------------------------------------ Quick Install ------------- Un-tar the expect-lite tar ball, and run the included install.sh Test by typing at the prompt: expect-lite If you see the help, then it is ready to go, installation is complete! Quick Start ----------- Expect-lite has many features which make it useful, and the documenation highlights those. But to start using expect-lite quickly, you require two items: 1. a script 2. a host Here is a quick script which you can paste into a file to test expect-lite, call it test.elt : ; ==== Ping localhost and report result ==== @5 >ping -c 2 localhost +$packet_rx=(\d+) received > >echo "Packets received are:$packet_rx" The second item you require is a host to run your script against. Expect-lite is designed to log into a remote host and run your script, as if a person was typing the commands. However that may require setting up ssh keys and so forth, and this is the Quick Start section. Type the following to run the above script on your localhost: expect-lite r=none c=test.elt There should be output that looks similar to the following: cvmiller@maile:~/Freescale$ cvmiller@maile:~/Freescale$ ping -c 2 localhost PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.053 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.056 ms --- localhost ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.053/0.054/0.056/0.007 ms cvmiller@maile:~/Freescale$ Assigned Var:packet_rx=2 cvmiller@maile:~/Freescale$ echo "Packets received:2" Packets received:2 ##Overall Result: PASS Congratulations you have just run your first expect-lite script! Quick Doc --------- To learn more about expect-lite please look at the documentation. expect-lite interprets the script based on the first character of the line. Here's a short list of what is available to get you started: > send to remote host, implies "wait for prompt" < _MUST_ be received, or script will report failure # are comment lines, and have no effect ; are printable (in stdout) comments, and have no other effect @ change the expect timeout value ? If statement, use format ?cond?action::else_action There are many more commands supported in expect-lite, it really is worth reading the documentation. BSD-Style License ----------------- Copyright (c) 2008-2015, Craig Miller Copyright (c) 2007, Freescale Semiconductor, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Freescale Semiconductor nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------ 15 January 2015 Celebrating 10 Years http://expect-lite.sourceforge.net/ this document for version 4.1.1 or later expect-lite.proj/pkgIndex.tcl0000644000076400007640000000103611551107071016751 0ustar cvmillercvmiller# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded expect-lite 4.0 [list source [file join $dir expect-lite]] expect-lite.proj/bashrc0000644000076400007640000000271512564335303015674 0ustar cvmillercvmiller# bashrc # append this sample bashrc to your .bashrc to set customize expect-lite # remote host to connect, default=none # expect-lite was designed to automate server farm environments # However, it can also be run from the local machine or PC by setting # this value to 'none'. The CLI option -r will overide this value #export EL_REMOTE_HOST=localhost # name of expect-lite script # Good for testing one script over and over #export EL_CMD_FILE= # change to this dir upon login #export EL_USER_DIR= # Login method to remote host # expect-lite includes a utilty (setup_local_ssh.sh) to automatically setup ssh # keys for the user to use with the localhost. This is the fastest method # of script execution, much faster than 'none'. # Choose one login method: telnet|ssh|ssh_key|none #export EL_CONNECT_METHOD=ssh_key export EL_CONNECT_METHOD=none # username for telnet|ssh|ssh_key access methods # User is also used by ssh_key method as well. If user is blank then the default # user will be used (the user running the script). However if $user is defined # then ssh_key will use the following command: ssh $user@$host #export EL_CONNECT_USER= # password for telnet|ssh access methods #export EL_CONNECT_PASS= # Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture # 100 ms is a good value for a local LAN, 200 ms if running across high speed internet #export EL_DELAY_WAIT_FOR_HOST= # User defined constants #export EL_* expect-lite.proj/Tools/0000755000076400007640000000000011416472246015605 5ustar cvmillercvmillerexpect-lite.proj/Tools/setup_local_ssh.sh0000755000076400007640000000434312564335303021334 0ustar cvmillercvmiller#!/bin/bash # # Script to setup local ssh keys # Allows ssh to localhost without password # # by Craig Miller 24 February 2010 # function usage { echo " $0 - Used to setup local SSH Key (e.g. ssh to \ localhost without a password challenge) " echo " e.g. $0" echo " " echo " By Craig Miller - Version: $VERSION" exit 1 } # Script Defaults numopts=0 VERSION=0.96 SSH_HOME=$HOME/.ssh while getopts "vV" options; do case $options in V ) show_version=TRUE let numopts+=1;; v ) show_version=TRUE let numopts+=1;; h ) usage;; \? ) usage # show usage with flag and no value exit 1;; * ) usage # show usage with unknown flag exit 1;; esac done # remove the options as cli arguments shift $numopts # check that there are no arguments left to process if [ $# -ne 0 ]; then usage exit 1 fi if [ $show_version ]; then usage exit 1 fi #======== Actual work performed by script ============ #check if ssh is installed if [ ! -x /usr/bin/ssh-keygen ]; then echo "===================" echo "ACK! ssh-keygen NOT installed!" echo "Please install ssh package before running $0" echo "===================" exit 1 fi #check if keys already exist if [ ! -e $SSH_HOME/id_rsa.pub ]; then mkdir -p $HOME/.ssh echo "===================" echo "Generating ssh keys" echo "===================" ssh-keygen -t rsa -N "" -f $SSH_HOME/id_rsa fi #check authorized_keys2 RESULT="" if [ -e $SSH_HOME/authorized_keys2 ]; then TEMP=`cat $SSH_HOME/id_rsa.pub` RESULT=`grep "$TEMP" $SSH_HOME/authorized_keys2` fi #create authorized key if [ "$RESULT" == "" ]; then echo "=======================" echo "Creating Authorized Key" echo "=======================" cd $SSH_HOME cat id_rsa.pub >> authorized_keys2 #return to previous directory cd - fi echo "===============" echo "Testing SSH Key" echo "===============" echo "ssh localhost" # this also adds localhost to known_hosts file ssh -o StrictHostKeyChecking=no localhost 'hostname; exit' ssh -o StrictHostKeyChecking=no $HOSTNAME 'hostname; exit' # Pau! echo "=======================================" echo "Setup of SSH Key on localhost Complete!" echo "=======================================" expect-lite.proj/examples/0000755000076400007640000000000012564335303016320 5ustar cvmillercvmillerexpect-lite.proj/examples/test_hibit.txt0000644000076400007640000000157211324732514021222 0ustar cvmillercvmiller# How to use this file # Lines that begin with '>' are sent to the tempest # Lines that begin with '<' _MUST_ be received from the tempest, or this config script will fail # Lines beginning with # are comment lines, and have no effect # Lines beginning with ; are printable (in stdout) comments, and have no other effect # Lines beginning with @ change the expect timeout value # # test of Dynamic Var # ~mod_common.inc # set timeout value to 5 seconds ; ==== Set Timeout ==== @5 >id cat > $local_char_test_file # Options Tests > #>test1 /\x00/tag=0x08000127 set=10 >>name//tag=0x08000127 #>test8 /\x00/tag=0x08000127 set=10 > >^D ##### Paste in Regex lines above #### @5 > sed -i -e 's/\xc3\xa1/\xe1/' $local_char_test_file > hexdump $local_char_test_file > od -c $local_char_test_file > #pau expect-lite.proj/examples/self_test_conditional.txt0000755000076400007640000001330412540225450023433 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of Conditionals implemented in expect-lite # and self tested (where possible) # Turn on warnings !set ::WARN 1 ; ==== Set Timeout ==== @4 ; ==== Static Varible Tests ==== $name=craig $telephone=723-9161 $var1=var1 $var2=var2 $age=25 $blank= > ; === Conditional Equals ? $name == craig ?>echo "hello123" ? $name == craig ?>echo "hello123" >echo $name $telephone ; === Conditional Not-Equals ? $name!=$telephone?; === NE; Print var name:$name > ? $name!=$telephone?; === NE; Print var name:$name %dont_echo #>echo "here" ; === Conditional new var assignment ? $name != $telephone ? $a=$telephone ? $name != $telephone ? $a=$telephone >echo "Print var a:$a " > ; === Conditional var re-assignment ?$name!=$telephone?$var1=$name > ?$name!=$telephone?$var1=$name > >echo "Print var var1:$var1 " ; === Compare numbers larger or equal ?$age <= 25 ? >echo "new age" ?$age <= 25 ? >echo "new age" echo "old age" ?$age<30 ? >echo "old age" echo "Warning" ?$age % 30 ? >echo "bad stuff" > > ; === Compare numbers with else (and spaces) ?$age > 30 ? >echo "old age" :: > echo "new age" ? $age > 30 ? >echo "old age" :: > echo "new age" $age? >echo "old age" :: > echo "new age" ?30>$age?>echo "old age"::> echo "new age" ; === Compare numbers with ipv6 address ?1<2?>echo "fd80::dead:1" ?1<2?>echo "fd80::dead:1" 2?>echo "fd80::dead:1"::>echo "ff01::02" ?1>2?>echo "fd80::dead:1"::>echo "ff01::02" #*TERM $check_ext=true ; === Capture with expect ? $check_ext == true ?+$module=^([a-z]+).+ext3 > >lsmod ?$check_ext==true?+$module=^([a-z]+).+ext3 > ; === show capture $module > ; === Capture with expect and colons $check_ext=true >cat /etc/passwd | grep nobody ? $check_ext == true ?+$module1=:[0-9]+:[0-9]+:([A-Za-z]+): :: ; ==== or not >echo $module1 <[Nn]obody ; === Reassign vars $age=35 ; === new age is $age > >echo "55" +$age=\n([0-9]+) ?$age>=55?>echo "Freedom at $age"::>echo "Keep on working" echo " Skipper" >echo "2" >echo "3" %SKIP2_AGE55 ; === Test conditional jump with label with spaces, and space at end of label ?$age==55?%move along, nothing to see >echo " Skipper" >echo "2" >echo "3" *FAIL %move along, nothing to see ; === Test conditional jump with indentation ?$age!=55?%move along, nothing to see > >echo " Skipper" >echo "2" >echo "3" <3 > %move along, nothing to see ; === Test conditional include ?$age==55?~test_include.txt > >echo "Pau" ? $empty == 0?; Empty is |$empty | $a=a $b=a ?if $a!=$b ?>echo "$a $b" $name=Joe Blow ?if$name==Joe Blow?>echo "Found $name" kill -s INT $PID > ; === Test making assignments in action and else_action ?IF no == craig ? $var1=$name :: $var2=$age > echo $var1 $var2 echo $var1 $var2 echo "not here" :: $var2=$telephone - echo $var1 $var2 echo "not here" :: ? $var1 == TRUE ? >echo "nested ifs" ; === issue ^C from if statement $one=1 >time sleep 3 ?IF $one != 0 ? >^C - ; === issue simple commmand as action $one=1 ?IF$one!=0?>pwd - ; === Compare numbers with else ?30>$age? >echo "old age" :: > echo "new age" ?IF30>$age?>echo "old age"::>echo "new age" ; === Test skip to non-existant label ?IF $name == Joe Blow ? %SKIP_TO_NOWHERE >echo "skip this line" #self check ; == age=$age > echo ZZ$age # self check, ZZ should never go to -1 - 0 ?%REPEAT_LOOP # check that above loop worked ?if $age > 0? *FAIL > >echo "Pau" > ; ======== Decrementing YY Loop ============= # do another loop! # Keep loop labels UNIQUE! %REPEAT_LOOP1 # decrement variable -$loop2 > ; == loop2=$loop2 # stop the run away loop > echo $loop2 # self check, loop2 should never go to -1 -<-1 ?if $loop2 > 0 ?%REPEAT_LOOP1 ; ======== Incrementing Loop ======== $max=10 $count=3 %REPEAT_LOOP2 # increment variable +$count # stop the run away loop >echo $count # self check, loop2 should never go to 12 -<12 ?if $count <= $max ?%REPEAT_LOOP2 > ; ======= Test incrementing string ====== $junk=test +$junk ; === junk is $junk # self check ?if $junk != test ? >echo FAIL :: >echo Good <\nGood > ; === Test conditional undefined ?$undef_var==$blank?>echo Good :: >echo FAIL <\nGood > ?$undef_var!=$blank?>echo FAIL :: >echo Good <\nGood > ?$undef_var==?>echo Good :: >echo FAIL <\nGood > #*INTERACT ; ==== All Pau! > #Pau! expect-lite.proj/examples/test_constant_defaults.txt0000644000076400007640000000031611324732513023635 0ustar cvmillercvmiller# # CoSim Vars # # Constant variables. # $rtl_path=/local/$USER >echo $rtl +$check=\n.+(proj) ?if $check == __NO_STRING_CAPTURED__ ? $rtl=$rtl_path/proj :: $rtl=$rtl_path ; === echo $rtl > #Pau! expect-lite.proj/examples/self_test_all.elt0000755000076400007640000000435211736042225021653 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z_-]+) ([0-9a-zA-Z_/-]+);\1=\2;g'` echo $PARAMS expect-lite c=$0 el=expect-lite d=$PWD $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Masquerade Test # Becomes a self running executable with bash script in the beginning # Takes getopts-like parameters and converts to expect-lite parameters # # # Requires expect-lite version 3.1.4 # # Self Test Suite for expect-lite, use connect_method=ssh_key # # NOTE: Not all tests will pass when running connect method=none # self_test_directives.txt & self_test_fork.txt will fail # @45 > > # default expect-lite app $el=expect-lite $test_host=localhost ######## Get PWD to pass to child tests >echo $PWD >pwd +$pwd=\n(/[a-zA-Z0-9/_.-]+) ######## Get host to pass to child tests # back door to get --r parameter !if { $::expectlite::remote_host == "none" } { set ::expectlite::user_namespace(test_host) "none" } >hostname ?if $test_host == none? :: +$test_host=\n([a-zA-Z0-9/_-]+) $test_host=localhost ######## set defaults $count=0 # number of tests to run $max_test_count=7 $fail=0 $self_test0=self_test_conditional.txt $self_test1=self_test_code_block.txt $self_test2=self_test_math.txt $self_test3=self_test_var_deref.txt $self_test4=self_test_basics.txt $self_test5=self_self_ide_test.txt $self_test6=self_test_fork.txt $self_test7=self_self_directive_test.txt %START_LOOP ; ******************** start self test: $self_test$count ******************** >$el r=$test_host c=$self_test$count el=$el test_host=$test_host d=$pwd echo $? <0 +$count ?if $count <= $max_test_count ? %START_LOOP > > > ; ******************** Self Tests Pass! ******************** > # pau! expect-lite.proj/examples/self_test_basics.txt0000755000076400007640000000622512532626203022402 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test Basic Functionality of Send '>' '>>' and Expect '<' '<<' # Self tested functionality # # Requires Expect-lite version 3.6.0 # # # Added additional expects (not expect, fuzzy expect) '-<' '~<' # # Requires Expect-lite version 4.7.0 # # Turn on warnings *WARN # Turn on debug and see the inside workings *DEBUG # set expect timeout @3 # set bash var NUM >NUM=5 >TAG="" >TESTSTR="This is an equation:(5+3)/2*2" ; === detect single value with no regex >echo $NUM <<5 > ; === detect HTML Tag (no regex using '<<') >echo $TAG << > ; === detect HTML Tag (with regex using '<') >echo $TAG <[<]H..L> > ; === look for no regex with parenthisis, plus, star >echo $TESTSTR <echo $TESTSTR echo $TESTSTR ; === collect equation >echo $TESTSTR +$equation=This is an equation:([0-9()/\*+]+) ; === Start BC (which has no prompt) >bc >$equation <<8 >> >^D > *NODEBUG ; === check NOT expect >echo "the answer is 42" -echo "9" -<8 *EXP_INFO ; === check variable name starts with underscore (v4.8.1) $_myvar=underscore >echo $_myvar echo "this is the $MIN to rise up" ~ > ; === check fuzzy expect - white space at end of line >echo "cccc is the $MIN " ~ ; === check fuzzy expect - hexidecimal >echo "ffff is the 0xbeef to rise up" ~ ; === check fuzzy expect - decimal >echo "gggg is the $MIN" ~<(10.5) ; === check fuzzy expect - variable in second parens, not fuzzy >echo "hhhh 7 the $MIN " ~echo "iiii 7 the 10 to rise up" ~echo "jjjj 12.5 the $MIN to rise up" ~echo "kkkk (705) the $MIN to rise up" ~echo "llll now is the time to rise up" #~uptime ~echo "zbbb is the ($MIN) to rise up" #~echo "zeee is the $MIN to rise up" #~' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test of Embedded Expect Random Functions in expect-lite # # Script will print seed. # To get reproducible random numbers, use seed= # on commandline. # ; ==== Set Timeout ==== @5 # Define random functions !proc set_random_seed { var } { # proc sets the random seed based on expect-lite variable $var ! set seed $::user_namespace($var) ! if { $seed == "none" } { ! set seed [clock seconds] ! expr srand($seed) ! } else { ! expr srand($seed) ! } ! puts "Seed is:$seed" !} !proc random { start end } { # proc returns random number in range start-end ! set range [ expr $end - $start ] ! return [expr int(rand()*$range) + $start] !} !proc randomize { var start end } { # proc sets expect-lite variable to random value in range start-end ! set ::user_namespace($var) [random $start $end] !} ; === Start Randomize example # Assign some bogus values to variables # this declares the variable, so that embedded expect can access this variable $x=1 $y=2 # set the default value of the random number gen (rng) seed to "none" $seed=none # allow constant to override variable # Normally constants will over-ride variables, but # because $seed is a user_namespace variable, and referenced that way in # the procedure set_random_seed, we use a trick, to set $seed to the value # of the constant $seed. $seed=$seed ; === initialize the rng !set_random_seed seed ; === Randomize expect-lite variables x & y # !randomize !randomize x 5 10 !randomize y 20 50 > ; === Display value of x is $x, y is $y > > #Pau! expect-lite.proj/examples/self_test_regress_all.elt0000755000076400007640000000466212462401001023375 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! with current directory $PWD # Little bootstrap bash script to run kick start expect-lite script expect-lite $0 -d $PWD $* exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Requires expect-lite version 4.3.0 # define user defined help ;;; Self Test Suite for expect-lite, use connect_method=ssh_key NOTE: Not all tests will pass when running connect method=none self_test_directives.txt & self_test_fork.txt will fail ;;; @5 > > # default expect-lite app $el=expect-lite $test_host=localhost ######## Get host to pass to child tests # back door to get --r parameter !if { $::expectlite::remote_host == "none" } { set ::expectlite::user_namespace(test_host) "none" } >hostname ?if $test_host == none? :: +$test_host=\n([a-zA-Z0-9/_-]+) #$test_host=localhost ######## Get PWD to pass to child tests >echo $PWD >pwd +$pwd=\n(/[a-zA-Z0-9/_.-]+) ######## Inside view of include file pass # peeks at test_failed and exposed value to script !proc inc_result { var_result } { ! if {$::expectlite::_el(test_failed)} { ! set ::expectlite::user_namespace(var_result) 1 ! } else { ! set ::expectlite::user_namespace(var_result) 0 ! } !} ######## set defaults $inc_failed=0 $reg_count=0 $fail=0 $blank= $self_test0=self_test_conditional.txt $self_test1=self_test_code_block.txt $self_test2=self_test_math.txt $self_test3=self_test_var_deref.txt $self_test4=self_test_basics.txt $self_test5=self_self_ide_test.txt $self_test6=self_test_fork.txt $self_test7=self_self_directive_test.txt $self_test8= [ $self_test$reg_count != $blank ; ******************** start self test: $self_test$reg_count ******************** ~$self_test$reg_count !inc_result inc_failed > # give indication that test has passed or failed ?if $inc_failed == 1? [ :: ; ******************** $self_test$reg_count PASSED ******************** ;red ******************** $self_test$reg_count FAILED ******************** ] +$reg_count ] > > ; ******************** Self Tests Complete! ******************** > # pau! expect-lite.proj/examples/self_test_var_deref.txt0000755000076400007640000000570611736066146023107 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test left-side variable dereference (requires version 3.10 or later) # Self tested functionality # # # # Turn on warnings *WARN @6 # quick regression check of the old style vars $first=this is a regression test line ;; === string is: $first $one=ONE $two=two $three=3 $four=four $gen$one=this is the first $gen$two=this is the second $gen$three=this is the third ;; === string is: $gen$one ;; === string is: $gen$two ;; === string is: $gen$three #self check ?if $gen$two == this is the second ? >echo Good :: >echo FAIL <\nGood ; === Test new Var Functionality === ; === Test assignment var into array var $ztest $count=0 $ztest$count=TEST # self test ?if $ztest$count != TEST ? >echo FAIL :: >echo Good <\nGood ; === Test increment var +$count ;; === count $count # self test ?if $count != 1 ? >echo FAIL :: >echo Good <\nGood ; === Test capture var into array var (fails in version pre-3.1.4) $test_string=this is a test # capture item >echo $test_string +$item$count=\n(t[ 0-9a-zA-Z._-]+)$ > # self test ?if $item$count != $test_string ? >echo FAIL :: >echo Good <\nGood ; === Test new Var Functionality in Loop with Randomness === ######################## include random and array functions ~tcl_functions.inc $max=14 ; ======== Small Loop ======== $count=8 %REPEAT_SMALL_LOOP ;; === loop $count !randomize x1 0 63 !bitwise x1 << 2 !randomize x2 0 255 !randomize x3 0 255 !randomize x4 0 255 !randomize x5 0 255 !randomize x6 0 255 !dec2hex x1 !dec2hex x2 !dec2hex x3 !dec2hex x4 !dec2hex x5 !dec2hex x6 !randomize inport 1 4 > $port_in_$count=$inport $mac_da$count=$x1:$x2:$x3:$x4:$x5:$x6 #check assignments $gen$count=test$count # self check ?if $gen$count == test$count ? >echo Good :: >echo FAIL <\nGood >echo $port_in_$count <[1-4] # increment variable +$count > ?if $count < $max ?%REPEAT_SMALL_LOOP ; == show #3 items of parray: $port_in_10 $mac_da10 > # multiple var deref, will only deref var $gen$one if followed by non-var char ; === Multiple var dereference $ABC=$gen$one $two$three$four ; $ABC ?if $ABC == this is the first two3four ? >echo Good :: >echo FAIL <\nGood ; === Dynamic Variable with custom prompt ; === Requires version 3.2.0 or later # make sure we are using bash >bash */myprompt $/ >export PS1="myprompt " > >echo here >echo there >echo "hear" +$catch=\n(hear) # may fail on slow machines ?if $catch == hear ? >echo Good :: >echo FAIL #<\nGood #restore prompt >export PS1="\$ " # reset user defined prompt *// >sleep 1 #~show_vars.inc #pau! expect-lite.proj/examples/test_while_loop.txt0000644000076400007640000000064111644607026022264 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # make this puppy run @3 $blank= >echo "hello ken" echo "if block" ] > ; === Nested While loops ; == should repeat "hello ken" 3 times, with 2 "bye now"s inside each outer loop > $i=0 [ $i < 3 >echo "hello ken" echo "bye now" > +$j ] +$i ] > *INTERACT ; === simple loop $i=0 [ $i < 3 >echo "hello ken2" echo "done" > expect-lite.proj/examples/self_test_fork.txt0000755000076400007640000000433212172571603022077 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS expect-lite c=$0 $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # FORK Directive Test # # Test sets up two sessions, creating uniquely named directories # in /tmp/ for each session, then switches sessions # Later in the test, it switches back, and does a pwd to check # that it is in the correct session # # Includes include file tcl_funtions.inc in session to ensure default # session is correctly initialized # # Requires expect-lite version 3.5.0 # **SHELL=bash $fork_session=MY_HOST $fork_session2=MY_2nd_HOST ; ======== "SESSION 0a" the default session # get default session pwd >pwd >pwd +$PWD=\n(/[a-zA-Z0-9/_-]+) @10 *FORK $fork_session ; ======== "SESSION 1a" > ; === Test file inclusion inside a session ~tcl_functions.inc > # show fork status *FORK >cd /tmp >mkdir $fork_session >cd $fork_session > >sleep 1; pwd ; == negative test *FORK this and that > ; == fork status test *FORK > *FORK $fork_session2 ;========== "SESSION 2a" >mkdir -p /tmp/session2 >cd /tmp/session2 >pwd > > >hostname >sleep 2 > *FORK $fork_session ;========== "SESSION 1b" > >pwd >pwd > >cd /tmp # remove temp directory >rmdir session2 > *FORK $fork_session ;========== "SESSION 1c" #/tmp/MY_HOST >pwd cd /tmp/ >rmdir /tmp/$fork_session > ; === switch back to original session (aka default) *FORK default ; ======== "SESSION 0b" >>pwd <$PWD > ; === check current session *FORK > #pau! expect-lite.proj/examples/test_var_dereference.txt0000644000076400007640000000234111324732514023235 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test of 2 pass var dereference # Also tests fail script include (and conditional fail script) # # fail script #*~test_interact.inc # set timeout value to 5 seconds ; ==== Set Timeout ==== @2 >id -<(joe|fred) ; ==== Define functions ==== !proc inc_var { var } { ! incr ::user_namespace($var) !} !set _el(test) "main" > # initial value of counter $counter=0 ~test_include.txt $mac_sa0=00:04:23:b2:f6:39 $mac_sa1=00:11:43:d2:5d:08 ; === Build bridge table entries $counter $mac1=$mac_sa$counter >echo $mac_sa$counter >echo "hello" ?IF $counter == 0 ? *~test_interact.inc >echo $mac1 >echo $TERM > # test 'dash' demarcation >echo $mac_sa0-$counter # increment counter !inc_var counter > ; === Build bridge table entries $counter >echo $mac_sa$counter <$mac_sa$counter >echo "good bye" $tap_logs=/tmp/tap* >echo $tap_logs > #pau expect-lite.proj/examples/test_sudo.txt0000644000076400007640000000210111601642730021060 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z_-]+) ([0-9a-zA-Z_/-]+);\1=\2;g'` echo $PARAMS expect-lite r=none c=$0 el=expect-lite d=$PWD $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test of sudo privilages from a script # # #timeout @5 # sudo password $pass=secret # source in native TCL function run_sudo !source sudo.tcl > # run the ID command with sudo privilages #!run_sudo id $pass >sudo id !sudo_pass $pass +$mygid=gid=[0-9]+\(([a-z]+)\) ; == my gid is: $mygid > #pau! expect-lite.proj/examples/test_screen.txt0000644000076400007640000000261211324732514021376 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test managing of screens implemented in expect-lite # @3 ; ==== Check for screen on the remote host > which screen screen > echo "screen 1" > >^A >^D screen > echo "screen 2" > >^A >^D screen -list screen -list | grep pts | sort | head -1 +$myscreen1=([0-9]+\.pts.[0-9]+.[a-z\- 0-9]+) >screen -list | grep pts | sort | tail -1 +$myscreen2=([0-9]+\.pts.[0-9]+.[a-z\- 0-9]+) ; ==== Enter screen2, ping and sleep, then detach > screen -r $myscreen2 # inside existing screen, kick it to get a prompt >^M > >ping -c 2 localhost +$packet_tx=([0-9]+) packets transmitted > sleep 2 > >^A >^D killall screen >ps ax | grep screen > #Wait for test to end (return of prompt) > #Pau! expect-lite.proj/examples/test_cond_loop.txt0000644000076400007640000000366011324732513022076 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of Conditionals looping in expect-lite # and self tested (where possible) ; ;; ======================================== ;; ===========TOP OF SCRIPT =============== ;; ======================================== ; ==== Set Timeout ==== @4 ; ==== Static Varible Tests ==== $name=craig $telephone=723-9161 $var1=var1 $var2=var2 $age=5 $loop2=4 # decrement variable !proc decr { var } { ! incr $var -1 ! return $var !} > ; === Conditional Equals ? $name == craig ?>echo "hello123" ? $name == craig ?>echo "hello123" >echo $name $telephone ; ======== Decrementing ZZ Loop ============ # do a loop! %REPEAT_LOOP ! incr user_namespace(age) -1 > ; == age=$age > echo ZZ$age - 0 ?%REPEAT_LOOP >echo "Pau" > ; ======== Decrementing YY Loop ============= # do another loop! # Keep loop labels UNIQUE! %REPEAT_LOOP2 # decrement variable -$loop2 > ; == loop2=$loop2 # stop the run away loop > echo $loop2 -<-1 ?if $loop2 > 0 ?%REPEAT_LOOP2 ; ======== Incrementing Loop ======== $max=5 $count=3 %REPEAT_INC_LOOP # increment variable +$count # stop the run away loop >echo $count -<7 ?if $count <= $max ?%REPEAT_INC_LOOP ; ======= Test incrementing string ====== $junk=test +$junk ; === junk is $junk > # #while loop - very convoluted, recommend repeat loop # $counter=0 # $max=10 # %WHILE_START # ?if $counter >= $max?%END_WHILE # ! incr user_namespace(counter) # >echo ZZ$counter # - expect-lite.proj/examples/test_self_include.txt0000644000076400007640000000267111324732514022560 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test: Test bash here doc # # Assumptions: bash # Platforms: anywhere bash runs # $include_run=/tmp/include.tcl $include_loop=/tmp/include_loop.txt @5 ; === Create the file using bash "here doc" >umask 0 >cat > $include_run <<'+++' >#!/usr/bin/expect >set loop_end [lindex $argv 0] >for {set count 0} {$count < $loop_end} {incr count} { > puts "; === Send a packet \$counter with scapy ===" > puts " " > puts ">grep key \$tmr_file | cut -b \$tmr_ipv4sa | head -\$counter | tail -1" > puts "+\$tmr_ipv4sa_addr=\n(0x\[0-9a-fA-F\]+)" > puts ">\$scapy 2> /dev/null" > puts ">a=Ether(src=\"\$macsa\",dst=\"\$macda\")/IP(src=\"\$tmr_ipv4sa_addr\", dst=\"\$ipv4da\")/\$PAD60/\$FCS" > puts ">sendp(a, iface=\"\$dut_if1\")" > puts " puts ">^D" > puts ">>" > puts ">" > puts "!inc_var counter" > puts ">" > > > >} >puts "Pau" >+++ ; === now look at the file >cat $include_run ; === change permissions >chmod u+x $include_run ; === Run the file >$include_run 2 #Pau! expect-lite.proj/examples/test_bash_here_doc.txt0000644000076400007640000000134611745065415022675 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # ;;; Test: Test bash here doc Assumptions: bash Platforms: anywhere bash runs $this=that ;;; $tempfile=junk ; === Create the file using bash "here doc" >cat > $tempfile <<'+++' >2+3 >3+4 >quit >+++ ; === now look at the file >cat $tempfile > #Pau! expect-lite.proj/examples/test_masquerade.txt0000755000076400007640000000253711405277740022264 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # determine OS (Mac, Linux, cygwin) OS=`uname -s` HOST=localhost case $OS in "Linux" ) SED_OPT=" -r ";; "Darwin" ) SED_OPT=" -E ";; "CYGWIN_NT-5.1" ) HOST=none; SED_OPT=" -r ";; * ) echo "Error: Unknown OS:$OS" exit 1;; esac # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed $SED_OPT 's;--([a-zA-Z]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS $HOME/bin/expect-lite r=$HOST c=$0 $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Masquerade Test # Becomes a self running executable with bash script in the beginning # Takes getopts-like parameters and converts to expect-lite parameters # # # Requires expect-lite version 3.1.4 !set WARN 1 $answer=42 $seed=5 # quick math =$answer * $seed > $ztest=zero ; === show ztest:$ztest > #~show_vars.inc > ; === Answer: $answer > expect-lite.proj/examples/test_vi.txt0000644000076400007640000000227111324732514020536 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # Test: tests editing with vi in expect-lite # Assumptions: vi is present # Platforms: i386 & CDS # # Source common variable file for this test suite ~mod_common.inc # Redefine test file to always be in /tmp $local_char_test_file=/tmp/p_short$DATE.txt ; ==== $local_char_test_file > > > sleep 1 > # If needed connect to DUT (PPC) ~$connect_manager @1 ; ==== Create Test File with vi >vi $local_char_test_file <~ >>:set noai >>:%d >>a >>STATEFUL_RULE: rule_1 >> RESET_STATE: >> EVENT "login" >> GV[1] = 0x02 >> report { GV[1]:4} >> next_state STATE_1 >> STATE STATE_1: >> EVENT "open" >> GV[1] = GV[1]+1 >> report { 'test' } >> report { GV[1]:4} >> EVENT "END_OF_SUI" >> GV[1] = GV[1]+1 >^[ >>:wq >clear # ==== end of test file >cat $local_char_test_file > expect-lite.proj/examples/test_expect_noregex.txt0000644000076400007640000000121611324734657023147 0ustar cvmillercvmiller # How to use this file # Lines that begin with '>' are sent to the tempest # Lines that begin with '<' _MUST_ be received from the tempest, or this config script will fail # Lines beginning with # are comment lines, and have no effect # Lines beginning with ; are printable (in stdout) comments, and have no other effect # Lines beginning with @ change the expect timeout value # # Test Expect no-regex feature # @5 *DEBUG $TEST=/proc/cpuinfo !source testit.tcl # set bash var NUM >NUM=5 >TAG="" > ; === detect single value >echo $NUM <<5 > !testit 5 > *SHOW VARS ; === detect HTML Tag >echo $TAG << > >echo $TAG <[<]H..L> > #Pau! expect-lite.proj/examples/debug.inc0000644000076400007640000000107011324732514020075 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # Jump to interact # ; Press '+++' to end interactive session > !interact +++ return > # allow script to continue !set _el(continue) 1 > ; === Continuing Script > expect-lite.proj/examples/test_bash_env.txt0000755000076400007640000000107512012310545021700 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # # Change the environment variables to match your environment # export EL_CONNECT_USER=user export EL_CONNECT_PASS=mysecret export EL_REMOTE_HOST=10.1.1.15 export EL_CONNECT_METHOD=telnet hostname # re-run the script as an expect-lite script /usr/bin/env expect-lite c=$0 $* # end the bash script, and return expect-lite pass/fail exit $? #start the expect-lite script *EXP_INFO @3 $myvar=hello world $user=admin >echo "$myvar" *INTERACT > expect-lite.proj/examples/test_el_lib.tcl0000755000076400007640000000506411715750420021317 0ustar cvmillercvmiller#!/usr/bin/env tclsh8.5 # # libexpect is compiled with tclsh version 8.5 # # expect-lite library demo script # # by Craig Miller 5 Feb 2011 # # Add library to search path lappend auto_path "." # Load el_lib package require expect-lite puts "el_lib loaded" # Initialize EL library # _el_init_library # Loads libexpect, initializes el global variables, spawns bash session # expectlite::_el_init_library "*EXP_INFO IP=10.5.5.5 *DEBUG" puts "el_lib initialized" # create spawn sessions and set prompt to identify the session spawn bash send "export PS1='0\$ '\n" set session(default) $spawn_id spawn bash send "export PS1='1\$ '\n" set session(dut1) $spawn_id spawn bash send "export PS1='2\$ '\n" set session(dut2) $spawn_id spawn bash send "export PS1='3\$ '\n" set session(dut3) $spawn_id # remove global to simulate STAF unset spawn_id # Import the session array into EL # _el_import_session_ids # e.g. _el_import_session_ids dut3 exp9 dut1 exp7 dut2 exp8 def exp6 # Note: TCL does not actually pass arrays, therefore a list is passed # expectlite::_el_import_session_ids [array get session] # # Import more vars into EL (as constants) # expectlite::_el_import_const "DUT=mydut *NOFAIL {my=this or that}" expectlite::_el_import_const "DUT2=thatdut " ################ initialization complete. Begin of script ############ proc test_funct { str } { puts "calling test_funct param=$str" sleep 3 return 0 } puts "argv0 is:$argv0" # read this file as el script, reference by buf_stack pointer set cmd_file $argv0 set cmd_list_ptr [expectlite::_el_buffer $cmd_file] # show first 20 lines of EL script #expectlite::_el_buffer_show 20 $expectlite::_el_buf(stack) 1 # call el script exec set RESULT [ expectlite::_el_script_exec "" $cmd_list_ptr ] # Print result of test switch $RESULT { 0 { puts "\nTest Passed" } 1 { puts "\nTest Failed" } 2 { puts "\nTest Abend" } } #stop TCLSH from reading EL Script exit 0 ########## Embedded EL Scrtpt ############### ; === start script $IP @2 *TIMESTAMP ISO $IP=2001::DEAD ~junk >date <2012 >pwd #*FORK > *NOTIMESTAMP $count=0 $max=3 %GEN_LOOP > ?if $test_complete == Done ?%BREAK_LOOP1 # increment variable +$count ?if $count <= $max ?%GEN_LOOP %BREAK_LOOP1 > $i=2 [ $i < 5 > ?if $i == 4 ?%BREAK_LOOP # increment variable +$i ] %BREAK_LOOP ; === test IPv6 addressing $platform=ppc ? $platform == i386 ? $my_addr=2001:db8::f00d :: $my_addr=2001:db8::feed ? $my_addr!=2001:db8::feed ? *FAIL *SHOW VARS *TCL puts "\nARGV:$argv0" *TCL puts [test_funct $cmd_list_ptr] >echo "pau" > expect-lite.proj/examples/test_not_expect.txt0000644000076400007640000000164111324732514022270 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test NOT expect feature using the '-<' # This test _should_ fail on Friday # # set timeout value to 5 seconds ; ==== Set Timeout ==== @5 >id id <(joe|craig|cmiller) #> echo "fred" ; === don't expect joe or fred >id <(craig|cmiller) -<(joe|fred) ; === fail if module include pm* >lsmod - ls -1 /dev/ttyS* ls -1 /dev/ttyS* -date +%A - #pau expect-lite.proj/examples/self_test_math.txt0000755000076400007640000000346212144036215022064 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test the math functions (requires version 3.10 or later) # # # # # Turn on warnings !set ::WARN 1 @3 ; == test of Math Functions > $num=5 $mult=2 =$num + 10*$mult ; === num is $num >echo $num <25 > =$num*10 ; === num is $num >echo $num <250 $num=5 =$num*10 / $num ; === num is $num >echo $num <10 $five=5 $answer=1 =$answer*$five/2.0 ; === answer is $answer >echo $answer <2.5 $five=5 $answer=1 =$answer*$five % 2 ; === answer is $answer >echo $answer <1 $five=5 $answer=1 =$answer + $five / 2 ; === answer is $answer >echo $answer <3 $five=5 ; == Negative test answer1 not defined then division, undefined should be initialized to zero =$answer1 / 2 * (10 + 1) # self check ?if $answer1 != 0 ? >echo FAIL :: >echo Good <\nGood ; === answer is $answer1 ; == Negative test answer1 not defined, but should work becuase of '+' =$answer1 + 2 * (10 + 1) ; === answer is $answer1 # self check ?if $answer1 != 22 ? >echo FAIL :: >echo Good <\nGood ; === Negative test: Arrays not supported, but concatination will occur $answer3=30 $count=3 $answer=5 =$answer$count + 5 ; === answer is $answer # self check ?if $answer != 58 ? >echo FAIL :: >echo Good <\nGood # Calculate and set test_timeout in seconds =$test_timeout + 60 * 2 @$test_timeout > ?if $test_timeout != 120 ? >echo FAIL :: >echo Good <\nGood > $answer=1 =$answer * pow(2,3) > ; == answer is: $answer > #Pau! expect-lite.proj/examples/expect-lite0000777000076400007640000000000012047470011023034 2../expect-liteustar cvmillercvmillerexpect-lite.proj/examples/test_include.inc0000644000076400007640000000115711461137261021477 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # This is a test include file # ; ==== Connect to the cosim and check for kernel errors & fail if found >dmesg | tail -10 >dmesg -c | egrep "Oops|BUG" | wc -l <[ ]*0 #Wait for test to end (return of prompt) > #Pau! expect-lite.proj/examples/self_test_code_block.txt0000644000076400007640000001104112462401001023174 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of Code Blocks implemented in expect-lite # and self tested (where possible) # Turn on warnings !set ::WARN 1 ; ==== Set Timeout ==== @4 *EXP_INFO ; === basic if code block ?if 1==1?[ >echo "if1 good" ] <\nif1 good > ; === if else code block ?if 1!=1?>echo "BAD" :: [ >echo "if2 good" ] <\nif2 good > ; === NEG: third if too many code blocks - should have warning ?if 1!=1? [:: [ >echo "if3 bad" ] -<\nif3 bad > ; === nested ifs ?if 1 == 1? ?if 2==2? [ >echo "good" ] $test=3 ; === nested ifs using code blocks ?if 1 < $test ? [ :: >echo "else 1" ?if 2 < $test ? [ :: >echo "else 2" >echo "good" ] ] # requires expect-lite 4.5.0 $test=4 ; === if then else - taking else path ?if 1 == $test ? [ >echo "bad" ]::[ >echo "good" ] -echo "good" ]::[ >echo "bad" ] -echo "bad" ]::[ >echo "good nested then, else" ] >echo "good" ]::[ >echo "bad" ] -echo "bad" ]::[ ?if 1 == 2? [ >echo "bad" ]::[ >echo "good nested then, else" ] ] -echo "hello ken2" echo "good" ; === while loop with break $i=0 [$i < 5 >echo "hello ken2" echo "good" ; === Nested While loops ; == should repeat "hello ken" 3 times, with 2 "bye now"s inside each outer loop > $i=0 [ $i < 3 >echo "hello ken" echo "bye now" > +$j ] +$i ] ?if $i == 3 ? >echo "good" ?if $j == 2 ? >echo "good" ; === Negative testing of code blocks #*INTERACT ; == while statement with an "else" statement (should execute else statement) ; === simple while loop $i=0 [$i < 2 >echo "looping $i" echo "good" ] *INFINITE_LOOP 35 ; == test blank arg2 > $blank= [3 == $blank >echo "blank" ] - ; === NEG: test just number > [3 >echo "blank3" ] > ; === extra right bracket > ] > ; === NEG: test with no closure [ 1 < 2 >echo "good" # empty open bracket [ ; === testing foreach loops $joe=dude $host=aaa $list=123 45 678 90 good [ $host = $list >echo $host ] echo $x ] @5 +$i ] <\n2 ?$x == 2? > echo good ; === testing string math - slices $big=12345678901234567890 $big=this is a test today =$big % 6-15 > ; === $big > ?if $big==is a test? >echo good ; === testing string math - literal search/replace $replace=abc,def,hig =$replace//,/ / > ; === $replace > ?$replace == abc def hig? >echo good ; === $replace > ?$replace==123 456 789? >echo good ; === bad $replace > ?$replace==123 456 789? >echo good ; === NEG: bad2 $replace > ?$replace==123|456|789? >echo good ; === reg1; $replace > ?$replace==123=456=789? >echo good ; === reg1/ $replace > ?$replace==123=456=789? >echo good ; $myip > ?$myip==50? >echo good ; === reg1 $replace > ?$replace==123-good+789? >echo good ; === reg1 $replace > ?$replace==123-456+789good? >echo good ; === reg1 $replace > ?$replace==123-+789? >echo good # put this at the end of the file, it tests jumping to the end of the file ; === NEG: just [ ] [ >echo "blank4" ] expect-lite.proj/examples/testit.tcl0000644000076400007640000000036311324734752020346 0ustar cvmillercvmillerproc testit { i } { for {set j 1} {$j<6} {incr j} { if {$j == 1} {set type "abc" } if {$j == 2} {set type "def" } if {$j == 3} {set type "hij" } if {$j == 4} {set type "lmn" } if {$j == 5} {set type "qrs" } puts "$j>$type" } } expect-lite.proj/examples/el_shell.elt0000755000076400007640000000106712037636662020633 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: http://expect-lite.sf.net/ # # EL Shell # # ;=== connected > *INTERACT > ; === Pau expect-lite.proj/examples/test_big_grab.txt0000644000076400007640000000216411324732513021654 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of Dynamic Variables implemented in expect-lite # ; ==== Set Timeout ==== @10 ; ==== Static Variable Tests ==== $name=craig $telephone=723-9161 ; ==== Define functions ==== !proc inc_var { var } { ! incr ::user_namespace($var) !} > # initial value of counter $counter=1 ; ==== Grab bunch of data === !inc_var counter >lsmod | grep snd | cut -b 1-20 | head -$counter | tail -1 +$bulk_data=\n(snd[a-z0-9_]+) !inc_var counter >lsmod | grep snd | cut -b 1-20 | head -$counter | tail -1 +$bulk_data1=\n(snd[a-z0-9_]+) !inc_var counter >lsmod | grep snd | cut -b 1-20 | head -$counter | tail -1 +$bulk_data2=\n(snd[a-z0-9_]+) > ; === Buld data is: $bulk_data > #pau expect-lite.proj/examples/self_test_ide.txt0000755000076400007640000000040511736041616021675 0ustar cvmillercvmiller# # Test expect-lite IDE (requires version 4.0.x or later) # ; ==== Testing the IDE ===== >echo line "1" >echo line "2" >echo line "3" >echo line "4" *INTERACT >echo "do not run this line" >echo line "6" >echo line "7" >echo line "8" >echo line "9" > #Pau! expect-lite.proj/examples/tcl_functions.inc0000644000076400007640000001102612532627746021677 0ustar cvmillercvmiller############################################################### # Heart of expect-lite crg (constrained random generator) lite # functions. The functions are called from expect-lite # # set_random_seed sets the random seed # random returns random number in range start-end # randomize # sets expect-lite variable to random value in range start-end # # Include file sets seed, and initialized Random Number Generator ################################################################ # # Additonal functions in this file # # dec2hex converts decimal a hexadecimal # incr_wrap # increments expect-lite var unless at $end, # then wraps to $start # # show_all_vars # Shows all defined expect-lite Vars using 'str' as filter # use "*" to show all defined variables # # mark_time # grabs current time (with milisecond resolution) and places value in var_name # # show_time # var_time_ms is time in miliseconds (from the epoch) returned by mark_time # returns date/time formatted string in var_name # ################################################################ # Updated for expect-lite 4.10 namespace - 8/18/11 # Updated with time functions (version 4.7.0) - 3/30/14 ########## Include file which 'sources' tcl functions # Define random functions !proc set_random_seed { var } { # proc sets the random seed based on expect-lite variable $var ! set seed $::expectlite::user_namespace($var) ! if { $seed == "none" } { ! set seed [clock seconds] ! expr srand($seed) ! set ::expectlite::user_namespace($var) $seed ! } else { ! expr srand($seed) ! } ! puts "Seed is:$seed" !} !proc random { start end } { # proc returns random number in range start-end ! set range [ expr $end +1 - $start ] ! return [expr int(rand()*$range) + $start] !} !proc randomize { var start end } { # proc sets expect-lite variable to random value in range start-end ! set ::expectlite::user_namespace($var) [random $start $end] !} > # # Define Additional Functions # !proc dec2hex { hex_var_name } { ! # A Procedure that converts decimal a hexadecimal value, updates expect-lite variable ! set x $::expectlite::user_namespace($hex_var_name) ! set x [format %02X $x] ! set ::expectlite::user_namespace($hex_var_name) $x !} !proc bitwise { var oper val } { # proc sets expect-lite variable to bitwise operation 'oper' by $val # supports oper: << >> & | ^ + = * / % # depricated by expect-lite math function ! set ::expectlite::user_namespace($var) [expr $::expectlite::user_namespace($var) $oper $val] !} > !proc incr_wrap { var start end } { # increments expect-lite var unless at $end, then wraps to $start ! if { $::expectlite::user_namespace($var) == [expr $end ] } { ! set ::expectlite::user_namespace($var) $start ! } else { ! incr ::expectlite::user_namespace($var) ! } !} > # Shows all defined expect-lite Vars using 'str' as filter !proc show_all_vars { str } { ! set var_list [array names ::expectlite::user_namespace] ! set var_list_sorted [lsort $var_list] ! puts "Displaying expect-lite Variables:" ! foreach i $var_list_sorted { ! if { $str != "*" } { ! if { [ regexp ".*$str.*" $i ] } { ! puts "Var:$i \t\t\Value:$::expectlite::user_namespace($i)" ! } ! } else { ! puts "Var:$i \t\t\Value:$::expectlite::user_namespace($i)" ! } ! } !} > # Time function: mark time, place into expect-lite variable (reference by name) !proc mark_time { var_name } { ! # A Procedure that marks current time in milliseconds and, updates expect-lite variable ! set time [clock clicks -milliseconds ] ! set ::expectlite::user_namespace($var_name) $time !} # Time function: converts time format (in miliseconds) and places into expect-lite variable (reference by name) !proc show_time { var_time_ms var_name} { ! # A Procedure that converts time from milliseconds and, updates expect-lite variable ! set date $::expectlite::user_namespace($var_time_ms) ! set ms [expr $date % 1000] ! set date [expr int($date / 1000)] ! set date_str [clock format $date -format "%Y-%m-%d %H:%M:%S"] ! set date_str "$date_str.$ms" ! set ::expectlite::user_namespace($var_name) $date_str !} # set the default value of the random number gen (rng) seed to "none" $seed=none # allow constant to override variable # Normally constants will over-ride variables, but # because $seed is a user_namespace variable, and referenced that way in # the procedure set_random_seed, we use a trick, to set $seed to the value # of the constant $seed. $seed=$seed ; === initialize the rng !set_random_seed seed #pau expect-lite.proj/examples/self_self_directive_test.txt0000755000076400007640000000422212545056774024136 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z_]+) ([0-9a-zA-Z]+);\1=\2;g'` echo "PARMS=$PARAMS" expect-lite r=localhost c=$0 el=expect-lite test_host=none $PARAMS d=$PWD exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Self Self Test of Expect-lite Directives # # Run as executable, not within expect-lite # # Runs another expect-lite self test, and monitors INFO & WARNings # # Requires ssh connection, timing issues with remote_host=none # # Requires expect-lite version 3.5.0 # # default expect-lite app # force use of Localhost (rather than none) $LOCALHOST=localhost @10 >$el r=$LOCALHOST c=self_test_directives.txt el=$el echo FAIL|else >echo Good|result0 echo $? <\n1 ; *********** Expect-lite Directive Test Pass! ************ > expect-lite.proj/examples/test_ed.txt0000644000076400007640000000242111324732513020504 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # Test: tests editing with ed in expect-lite # Assumptions: ed is present # Platforms: i386 & Full Linux Distros (like Ubuntu PPC) # # Source common variable file for this test suite #~mod_common.inc # Redefine test file to always be in /tmp $local_char_test_file=/tmp/test_ed_data.txt ; ==== $local_char_test_file > > > @1 ; ==== Create Test File with ed >ed -p "# " $local_char_test_file >%d >a >>STATEFUL_RULE: rule_1 >> RESET_STATE: >> EVENT "login" >> GV[1] = 0x02 >> report { GV[1]:4} >> next_state STATE_1 >> STATE STATE_1: >> EVENT "open" >> GV[1] = GV[1]+1 >> report { 'test' } >> report { GV[1]:4} >> EVENT "END_OF_SUI" >> GV[1] = GV[1]+1 >>. >wq # number of bytes in file <\n[0-9]+ > # ==== end of test file ; === set timeout to 10 @10 ; ==== Display test file created with ed >cat $local_char_test_file expect-lite.proj/examples/pkgIndex.tcl0000644000076400007640000000103612117224047020571 0ustar cvmillercvmiller# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded expect-lite 4.0 [list source [file join $dir expect-lite]] expect-lite.proj/examples/test_includer.txt0000644000076400007640000000343311461137261021726 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # determine OS (Mac, Linux, cygwin) OS=`uname -s` HOST=localhost case $OS in "Linux" ) SED_OPT=" -r ";; "Darwin" ) SED_OPT=" -E ";; "CYGWIN_NT-5.1" ) HOST=none; SED_OPT=" -r ";; * ) echo "Error: Unknown OS:$OS" exit 1;; esac # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed $SED_OPT 's;--([a-zA-Z]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS #$HOME/bin/expect-lite r=$HOST c=$0 $PARAMS $HOME/Expect-lite/2expect-lite r=$HOST c=$0 $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: http://lancelot.am.freescale.net/~craig/Docs/expect-lite.html # # test of Dynamic Var # #~mod_common.inc $manarch=i386 # set timeout value to 5 seconds ; ==== Set Timeout ==== @3 >id cd $tmp > pwd >if [ $manarch = i386 ]; then >echo "test_include.txt" >else >echo "ppc" >fi *INFINITE_LOOP 10 >echo hello *INFINITE_LOOP abc >sleep 2 *INTERACT > echo hello ?if 1 == 1 ? %PAU !puts "here" !puts "there\n" >> pwd +$P=\n/home/([a-z]+) >echo "test_include.txt" +$INCLUDE=\n([0-9a-zA-Z\._]+) #~$INCLUDE ~test_include.txt %PAU >echo "Returned from include file" -echo "[test]" <<[test] >echo tfile_$RANDOM +$temp_file=\n(tfile_[0-9]+) *INTERACT > #pau expect-lite.proj/examples/ols2010_example.elt0000644000076400007640000000362211416731707021647 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # determine OS (Mac, Linux, cygwin) OS=`uname -s` HOST=localhost case $OS in "Linux" ) SED_OPT=" -r ";; "Darwin" ) SED_OPT=" -E ";; "CYGWIN_NT-5.1" ) HOST=none; SED_OPT=" -r ";; * ) echo "Error: Unknown OS:$OS" exit 1;; esac # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed $SED_OPT 's;--([a-zA-Z_]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS $HOME/bin/expect-lite r=$HOST c=$0 $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # OLS 2010 Example Script by Craig Miller, July 2010 # # Web Client & Server Identification # # # # # set timeout to 10 seconds @10 #Get sudo password from env variable $SUDO_PASS=$EL_rootpass $WEB_SERVICE=http://www.w3.org/ $WEB_SERVICE=http://www.linuxsymposium.org/ # start packet capture *FORK tcpdump >echo $SUDO_PASS | sudo -S tcpdump -i eth0 -s 256 -e -X portrange 80 | egrep -A 10 'org.www' # force expect-lite to wait until tcpdump is ready <\nlistening on wget -S --spider $WEB_SERVICE # verify server in wget output <sleep 2 > # check packets captured *FORK tcpdump # verify client >^C ; === Pause to break >sleep 2 > #*INTERACT >> > expect-lite.proj/examples/test_help.txt0000644000076400007640000000454411324732514021055 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test: Test Help - shows help if swroot is not defined on cli # # Assumptions: # Platforms: i386 & CDS & Mac Linux # $swroot=NONE !proc printstr { str } { ! set TERM_BLUE {} ! set TERM_NORM {} ! regsub -all ";" $str "" str ! set mystring [join $str "\n"] ! puts "\n$TERM_BLUE$mystring$TERM_NORM" !} !set help_text { !" rtl.elt: a Simple Sanity Script for RTL and DP software" !" Usage: expect-lite r=localhost c=rtl.elt swroot= " !" " !" additional options: " !" co_rtl_dir= Path to RTL, default: /local/$USER" !" rtl_delete=yes Deletes rtl in rtl directory and does a fresh checkout" !" dp_delete=yes Deletes dp software tree and does a fresh checkout" !" " !} ! > # Show help if swroot has not been defined ?IF $swroot == NONE ? :: %NO_HELP_TEXT > > ; === Show Help === ; === Show Help === # This help uses printable comments (unbuffered) # start blue text ;; ;; rtl.elt: a Simple Sanity Script for RTL and DP software ;; Usage: expect-lite r=localhost c=rtl.elt swroot= ;; ;; additional options: ;; co_rtl_dir= Path to RTL, default: /local/$USER ;; rtl_delete=yes Deletes rtl in rtl directory and does a fresh checkout ;; dp_delete=yes Deletes dp software tree and does a fresh checkout # end blue text ;; > ! _el_fail_test %NO_HELP_TEXT $FCS=Padding("1234") ; === Show all Vars Defined !set var_list [array names user_namespace] !set var_list_sorted [lsort $var_list] !foreach i $var_list_sorted { ! puts "Var:$i \t\t\Value:$user_namespace($i)" !} > ; ================================= ; === Press '+++' to exit interactive session !interact +++ return > ; === Script is continuing ; ================================= ; === Show all Const Defined !set var_list [array names cli_namespace] !set var_list_sorted [lsort $var_list] !foreach i $var_list_sorted { ! puts "Var:$i \t\t\Value:$cli_namespace($i)" !} > #Pau! expect-lite.proj/examples/test_dyn_var.txt0000644000076400007640000000376311324732513021570 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test of Dynamic Variables implemented in expect-lite # ; ==== Set Timeout ==== @10 ; ==== Static Varible Tests ==== $name=craig $telephone=723-9161 > >echo $name $telephone > ; ==== Dynamic Variable Tests ==== >ping -c 2 localhost +$packet_rx=([0-9]+) received >echo $packet_rx >/sbin/lsmod +$nfsd_size=nfsd[ \t]+([0-9]+)[ \t]+[0-9] >env | sort +$home=\nHOME=([a-z/]+) +$shell=^SHELL=([a-z/]+) uname -a +$host=Linux ([a-z\-0-9]+) > >hostname +$hostname=(came[a-z\-0-9]+|temp[a-z\-0-9]+) >echo "0$USER" +$user=0([a-z]+) > > /sbin/ifconfig eth0 +$host_addr=inet addr:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) @10 ; ==== Dynamic Variables and Shell Variables ==== > bash > SHDATE=`date +_%Y_%m_%d_%H:%M:%S` # Create expect-lite DATE Var > > echo $SHDATE +$DATE=\n(_.*) ; ==== Dynamic Variables managing screen ==== # setup screens # screen 1 > screen > >^A >^D screen > >^A >^D screen -list screen -list | grep pts | sort | head -1 +$myscreen1=([0-9]+\.pts.[0-9]+.[a-z\- 0-9]+) >screen -list | grep pts | sort | tail -1 +$myscreen2=([0-9]+\.pts.[0-9]+.[a-z\- 0-9]+) ; ==== Enter screen2, ping and sleep, then detach > screen -r $myscreen2 # inside existing screen, kick it to get a prompt >^M > >ping -c 2 localhost +$packet_tx=([0-9]+) packets transmitted > sleep 2 > >^A >^D killall screen >ps ax | grep screen > > #Pau! expect-lite.proj/examples/test_fork_web_client_server.txt0000644000076400007640000000262411324732514024644 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS expect-lite r=none c=$0 $PARAMS exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # FORK Directive Test # Utilizes FORKs to control web client and monitor server log # # # Requires expect-lite version 3.2.0 # $wget=wget --no-proxy -O /dev/null http://localhost/ $server_log=/var/log/apache2/access.log $fork_session=WEB_SERVER ; === get date to match in server log later > SHDATE=`date +date%Y:%H:%M` > echo $SHDATE +$DATE=\ndate(.*) @10 *FORK $fork_session ; ======== "WEB_SERVER 1a" > ; === Tail the server log >tail -f $server_log # clear the expect buffer >> *FORK default ;========== "WEB_CLIENT 2a" >echo "make web request" >$wget *FORK $fork_session ;========== "$fork_session 1b" >> <127\.0\.0\.1.*$DATE.*Wget >^C >> >sleep 2 #pau! expect-lite.proj/examples/self_self_ide_test.txt0000755000076400007640000000363712545056774022732 0ustar cvmillercvmiller#!/usr/bin/env bash # make this auto-runnable! # Little bootstrap bash script to run kick start expect-lite script # Convert --parms to expect-lite param=value format PARAMS=`echo $* | /bin/sed -r 's;--([a-z_]+) ([0-9a-zA-Z]+);\1=\2;g'` echo $PARAMS expect-lite r=localhost c=$0 el=expect-lite test_host=none $PARAMS d=$PWD exit $? # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Self Self Test of Expect-lite IDE commands # Runs another expect-lite self test, and drives IDE # # Requires ssh connection, timing issues with remote_host=none # # Requires expect-lite version 4.0.x # # default expect-lite app # force use of Localhost (rather than none) $LOCALHOST=localhost @10 >$el r=$LOCALHOST c=self_test_ide.txt el=$el <`h h this Help ; === check last 5 lines >`-5 <echo line "1" <<>echo line "2" <<>echo line "3" <<>echo line "4" ; === check next 5 lines >`5 <echo "do not run this line" <<>echo line "6" <<>echo line "7" <<>echo line "8" <<>echo line "9" ; === Skip next line >`k echo "do not run this line" ; === Show current line >`0 Printing current line of script: >echo "do not run this line" ; === show vars >`v `c echo $? <\n0 ; *********** Expect-lite IDE Test Pass! ************ > expect-lite.proj/examples/sudo.tcl0000644000076400007640000000137211601642730017775 0ustar cvmillercvmiller# Native Expect function to handle sudo prompt # sudo is sometimes challenged by a password, and sometimes not # # by Craig Miller June 2010 # proc run_sudo { cmd pass } { global expect_out upvar expectlite::DEBUG DEBUG send "sudo -p 'sudo# ' $cmd \n" expect -timeout 1 -notransfer -re "\nsudo# " { send "$pass\n"; puts "sendpass\n"} # wait for bash prompt #expect -re {.*\$ $} { } if { $DEBUG } { puts " in<<$expect_out(buffer)>>" puts "\n" } } proc sudo_pass { pass } { global expect_out upvar expectlite::DEBUG DEBUG expect -timeout 1 -notransfer -re {\[sudo\] password} { send "$pass\n"; puts "sendpass\n"} # wait for bash prompt #expect -re {.*\$ $} { } if { $DEBUG } { puts " in<<$expect_out(buffer)>>" puts "\n" } } expect-lite.proj/examples/test_include.txt0000644000076400007640000000021611461137261021540 0ustar cvmillercvmiller# include File !set user_namespace(el_script) $cmd_file > #*INTERACT >sleep 3 > ; === Script: $el_script $HELLO=Hi There > echo $HELLO ' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test of Prompt Detection # # set timeout value to 5 seconds ; ==== Set Timeout ==== @5 >id pwd > echo $PS1 #>sleep 1 > pwd +mypwd=\n([/a-z\-A-Z0-0]+) $thisvar=abc(def > echo $thisvar echo $thisvar echo $thisvar echo $this >echo "32" <3[1-2] $set=1 2 3 4 5 >for i in $set >{ >echo $i >} $max=5 >i=0 >while [ $i -lt $max ] >do >echo $i >let i+=1 >done <1 <2 <3 <4 $max=4 >if [ $max -ne 5 ]; then >echo "max is not equal to 5" >else >echo "we have a winner" >fi >PROC=`uname -i` >if [ "$PROC" == "i386" ]; then >echo proc20 >else >echo proc100 >fi +loop_counter=\nproc([0-9]+) $local_char_test_file=/tmp/junk > cat > $local_char_test_file ##### Paste in Regex lines below #### >>T00001/a(?$XL.*)/tag=0x08000001 >>T00002/b(?$XR.*)/tag=0x08000002 >>T00003/c(?$XO[0-7]*)/tag=0x08000003 >>T00004/d(?$XH[0-9A-F]*)/tag=0x08000004 >>T00005/e(?$XD[0-9]*)/tag=0x08000005 >^D #>^D > >cat $local_char_test_file > > #pau expect-lite.proj/examples/test_expect_include.txt0000644000076400007640000000015711324732513023113 0ustar cvmillercvmiller# test include file !set mytest "Hello" !puts $mytest !proc printit {var } { ! puts "printit:$var" !} ! #pau expect-lite.proj/examples/test_expect.txt0000644000076400007640000000702711324732514021414 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # For more info see: expect-lite.html # # test of Embedded Expect commands # # set timeout value to 5 seconds ; ==== Set Timeout ==== @5 >id <(craig|cvmiller) $tmp=/tmp/ $junk=orbit-root $junk2=$junk/some/path > cd $tmp > pwd # Useful Embedded Expect Functions # Define random function to be used in testing !proc random { start end } { ! set range [ expr $end - $start ] ! return [expr int(rand()*$range) + $start] !} ! # Define Match function with similar command as expect-lite and expect-lite failure mechanism !proc < { str } { #! puts $str ! expect -re $str { return } timeout { puts "\n\tExpect Failed:$str"; _el_fail_test } !} # Send function with similar command as expect-lite !proc > { str } { ! wait_for_prompt ! send "$str\n" !} # Define function to NOT match passed string. If found FAIL test !proc !< { str } { # Grab all text to prompt ! expect ".* $" ! catch { set ebuffer $expect_out(buffer)} ! if {[string first $str $ebuffer] != -1 } { ! puts "=============================Found $str ==========================" ! _el_fail_test ! } # Send out a return to kick a new prompt ! send "\n" !} > !# !puts "\nhello" !puts "EL->$user_namespace(junk2)" !puts "Expect timeout is: $timeout" > ; ==== Set up a var !set arch $::cli_namespace(manarch) !if { $arch == "ppc" } { ! puts "\narch IS $arch\n" ! } else { ! puts "\narch is NOT ppc, but $arch\n" ! _el_fail_test ! } ! #; ==== and more expect lines !set line ">echo too bad" !puts "EL->$::user_namespace(junk2)" !puts "Expect timeout is: $::timeout" !send "ls\n" !expect -re "tmp" { puts "got tmp"} "rand" { puts "got rand" } default {puts "\ngot nothing"} ; === Short TCL Test with globals !set ::TEST "Globals!" !set ruleFile "rule.txt" !proc global_test {} { ! global TEST ! upvar ruleFile lruleFile ! set scanResult 0 ! puts "Got there \n" ! puts "Got $lruleFile" ! puts "Globals:$TEST" !} !# Main !global_test ! > # print tuples in a list (such as 0xFF 123) !proc print_tuple_str { str } { ! set len [llength $str] ! set i 0 ! while {$i < $len} { ! set tag [lindex $str $i] ! incr i ! set count [lindex $str $i] ! incr i ! puts "$tag\t$count" ! } !} ; === Example of upvar instead of globals !set globalstr "Func printstr" ! !proc printstr { str } { ! upvar globalstr _globalstr ! regsub -all ";" $str "" str ! set mystring [join $str "\n"] ! puts $_globalstr ! puts $mystring !} ! !set mylist { ! "this" ! "that" ! "another" ! "EVENT \"login\"" ! } ! !printstr $mylist > ; === For Loop calling function defined in a different Embedded Expect Island !for {set j 1} {$j<6} {incr j} { ! if {$j == 1} {set type "1" } ! if {$j == 2} {set type "2" } ! if {$j == 3} {set type "3" } ! if {$j == 4} {set type "4" } ! if {$j == 5} {set type "5" } ! ! printstr $type !} !set mylist { ! "two" ! "three" ! "four" ! } !printstr $mylist > ; ==== Test access to expect-lite variables $TMP=test !puts "1->$cli_namespace(manarch)" !set TEST $user_namespace(TMP) !puts "2->$TEST" !if {$cli_namespace(manarch) == "ppc"} { ! set TEST "end_test.inc" ! puts "3->$TEST" !} !set user_namespace(TMP) $TEST !puts "4->$user_namespace(TMP),$TEST" > ; == Show the value of TMP:$TMP > #~$TEST > > echo "All Pau\\" > #pau expect-lite.proj/examples/test_increment.txt0000644000076400007640000000211211324732514022076 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of incrementing in expect-lite # and self tested (where possible) ; ==== Define functions ==== !proc inc_var { var } { ! incr ::user_namespace($var) !} > ; ==== Set Timeout ==== @4 ; ==== Static Varible Tests ==== $name=craig $telephone=723-9161 $var1=var1 $var2=var2 $age=25 ; === Show all Vars Defined !set var_list [array names user_namespace] !set var_list_sorted [lsort $var_list] !foreach i $var_list_sorted { ! puts "Var:$i \t\t\Value:$user_namespace($i)" !} > ; $testing_$age !inc_var age > ; $testing_$age !inc_var age > ; $testing_$age !inc_var age > ; $testing_$age !inc_var age > ; ==== All Pau! > #Pau! expect-lite.proj/examples/show_vars.inc0000644000076400007640000000037011324732514021024 0ustar cvmillercvmiller# Shows all defined expect-lite Vars ; === Show all Vars Defined !set var_list [array names user_namespace] !set var_list_sorted [lsort $var_list] !foreach i $var_list_sorted { ! puts "Var:$i \t\t\Value:$user_namespace($i)" !} > >sleep 1 > > expect-lite.proj/examples/self_test_fail_script.txt0000644000076400007640000000022411736042225023424 0ustar cvmillercvmiller# Self Test Fail Script ; === In Fail Script $FAIL=1 ; === FAIL=$FAIL # back door to continue after fail script #!set expectlite::_el(continue) 1 > expect-lite.proj/examples/test_expect_sm.txt0000644000076400007640000000334311324732514022110 0ustar cvmillercvmiller# How to use this file # Lines that begin with '>' are sent to the tempest # Lines that begin with '<' _MUST_ be received from the tempest, or this config script will fail # Lines beginning with # are comment lines, and have no effect # Lines beginning with ; are printable (in stdout) comments, and have no other effect # Lines beginning with @ change the expect timeout value # # test of Embedded Expect commands # #~mod_common.inc # set timeout value to 5 seconds ; ==== Set Timeout ==== @5 >id <(craig|cvmiller) $tmp=/proj/regression/tmp/generalRegression/tc_gzip_reserve.elt/ $junk=orbit-root $junk2=$junk/some/path > cd $tmp > pwd > !# !puts "\nhello" !puts "EL->$::unamespace(junk2)" !puts "Expect timeout is: $::timeout" !puts "The tempest is: $::tempest" > ; ==== Set up a var !set arch $::Cnamespace(manarch) !if { $arch == "ppc" } { ! puts "\narch IS $arch\n" ! } else { ! puts "\narch is NOT ppc, but $arch\n" ! _el_fail_test ! } ! > !puts "EL->$::unamespace(junk2)" !set ::unamespace(junk2) "this space" !puts "EL->$::unamespace(junk2)" ! > ; == $junk2 > #$TEST=NONE !puts "->$Cnamespace(manarch)" #!set TEST $unamespace(TEST) #!puts "->$TEST" !if {$Cnamespace(manarch) == "ppc"} { ! set TEST "test_include.inc" !} !set unamespace(TEST) $TEST !puts "->$unamespace(TEST),$TEST" > > ; == $TEST > ~$TEST > !set ruleFile "rule.txt" !for {set j 1} {$j<6} {incr j} { ! if {$j == 1} {set type "1" } ! if {$j == 2} {set type "2" } ! if {$j == 3} {set type "3" } ! if {$j == 4} {set type "4" } ! if {$j == 5} {set type "5" } ! ! puts "$j>$type" #! $i = $k !} !set mylist { ! "two" ! "three" ! "four" ! } !puts "Rule:$ruleFile" !puts "test $TEST" > > > echo "All Pau\\" > #pau expect-lite.proj/examples/test_var_deref.txt0000644000076400007640000000330011324732514022047 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # Test left-side variable dereference (requires version 3.10 or later) # # # # @3 # quick regression check of the old style vars $first=this is a regression test line ;; === string is: $first $one=ONE $two=two $three=3 $gen$one=this is the first $gen$two=this is the second $gen$three=this is the third ;; === string is: $gen$one ;; === string is: $gen$two ;; === string is: $gen$three ?if $gen$two == this is the second ? >echo Good :: >echo FAIL $port_in_$count=$inport $mac_da$count=$x1:$x2:$x3:$x4:$x5:$x6 #check assignments $gen$count=test$count ?if $gen$count == test$count ? >echo Good :: >echo FAIL echo $port_in_$count <[1-4] # increment variable +$count > ?if $count < $max ?%REPEAT_SMALL_LOOP ; == show #3 items of parray: $port_in_10 $mac_da10 > !show_all_vars mac_da > >sleep 1 #pau! expect-lite.proj/examples/self_test_directives.txt0000755000076400007640000000205712120413110023256 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # # Test expect-lite directives (requires version 3.5.0 or later) # *NODEBUG # Turn on warnings *WARN @3 ; === Check hello at beginning of test >echo hello +$answer=\n(hello) # self check ?if $answer != hello ? >echo FAIL :: >echo Good <\nGood # set tcsh for test, but not at beginning of file **SHELL=tcsh # set End of Line Sequence (eols) *EOLS CRLF > *EOLS LF *NOFAIL > *~self_test_fail_script.txt >echo "hello" # self check ?if $temp != fine ? >echo FAIL :: >echo Good <\nGood > > *NOWARN ; === See no warning @1 > sleep 2 > > *WARN > ; === See prompt timeout warning @1 > sleep 2 > > > > ; === Check timeout error @two > *INFO ; === check logging *LOG /tmp/$arg0.log >echo hello > *NOLOG ; === check log >grep hello /tmp/$arg0.log <\nhello > *LOG /tmp/$arg0.log >echo goodbye > *NOLOG > ; === check log append >egrep 'hello|goodbye' /tmp/$arg0.log <\nhello <\ngoodbye >rm /tmp/$arg0.log > ; === check log with no permissions *LOG /root/$arg0.log >echo hello > > #Pau! expect-lite.proj/examples/test_conditional.txt0000644000076400007640000000747311324732513022433 0ustar cvmillercvmiller# How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: expect-lite.html # # test of Conditionals implemented in expect-lite # and self tested (where possible) ; ==== Set Timeout ==== @4 ; ==== Static Varible Tests ==== $name=craig $telephone=723-9161 $var1=var1 $var2=var2 $age=25 > ; === Conditional Equals ? $name == craig ?>echo "hello123" ? $name == craig ?>echo "hello123" >echo $name $telephone ; === Conditional Not-Equals ? $name!=$telephone?; === NE; Print var name:$name > ? $name!=$telephone?; === NE; Print var name:$name %dont_echo #>echo "here" ; === Conditional new var assignment ? $name != $telephone ? $a=$telephone ? $name != $telephone ? $a=$telephone >echo "Print var a:$a " > ; === Conditional var re-assignment ?$name!=$telephone?$var1=$name > ?$name!=$telephone?$var1=$name > >echo "Print var var1:$var1 " ; === Compare numbers larger or equal ?$age <= 25 ? >echo "new age" ?$age <= 25 ? >echo "new age" echo "old age" ?$age<30 ? >echo "old age" echo "Warning" ?$age % 30 ? >echo "bad stuff" > > ; === Compare numbers with else (and spaces) ?$age > 30 ? >echo "old age" :: > echo "new age" ? $age > 30 ? >echo "old age" :: > echo "new age" $age? >echo "old age" :: > echo "new age" ?30>$age?>echo "old age"::> echo "new age" # $check_ext=true ; === Capture with expect ? $check_ext == true ?+$module=^([a-z]+).+ext3 > >lsmod ?$check_ext==true?+$module=^([a-z]+).+ext3 > ; === show capture $module > ; === Capture with expect and colons $check_ext=true >cat /etc/passwd | grep nobody ? $check_ext == true ?+$module1=:99:99:([A-Za-z]+): :: ; ==== or not >echo $module1 >echo "55" +$age=\n([0-9]+) ?$age>=55?>echo "Freedom at $age"::>echo "Keep on working" echo " Skipper" >echo "2" >echo "3" %move along, nothing to see ; === Test conditional jump with indentation ?$age!=55?%move along, nothing to see > >echo " Skipper" >echo "2" >echo "3" <3 > %move along, nothing to see ; === Test conditional include ?$age==55?~test_include.txt ; === Test conditional jump ?$age==55?%SKIP2_AGE55 >echo " Skipper" >echo "2" >echo "3" %SKIP2_AGE55 > >echo "Pau" ? $empty == 0?; Empty is |$empty | $a=a $b=a ?if $a!=$b ?>echo "$a $b" $name=Joe Blow ?if$name==Joe Blow?>echo "Found $name" kill -s INT $PID > ; === Test making assignments in action and else_action ?IF no == craig ? $var1=$name :: $var2=$age > echo $var1 $var2 echo $var1 $var2 echo "not here" :: $var2=$telephone - echo $var1 $var2 echo "not here" :: ? $var1 == TRUE ? >echo "nested ifs" ; === Test skip to non-existant label ?IF $name == Joe Blow ? %SKIP_TO_NOWHERE >echo "skip this line" ; ==== All Pau! > #Pau! expect-lite.proj/examples/el_run.php0000644000076400007640000000525212117226002020306 0ustar cvmillercvmiller ",$n, "
"; } } ?> EL runner

EL Web Runner


"; echo " Run: "; echo " args: "; //echo " in Week: "; echo " "; echo " "; echo "Available tests:
"; $dir_list=read_dir($path); show_dir($dir_list); } else { $el_app=$_POST["el_app"]; $el_args=$_POST["el_args"]; echo "You are looking at: $el_app"; echo "
";
	// show_dir(read_dir($path));
	$pipe = popen ("export TERM=web; $path/$el_app $el_args *NOINTERACT", "r");
	//$pipe = popen ("export TERM=web; $path/expect-lite $path/$el_app $el_args *NOINTERACT", "r");
	while(!feof($pipe)) {
		$line = fread($pipe, 1024);
		echo $line;
		// show partial output
		flush();	
	}
	pclose($pipe);
	echo "
"; } ?>
el-web-runner by Craig Miller © 2013
expect-lite.proj/examples/foreach_mypass.txt0000755000076400007640000000207012150145736022066 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # make this puppy run # How to use this expect-lite file, Lines that begin with: # '>' send to remote host, implies "wait for prompt" # '<' _MUST_ be received from the remote host, or this config script will fail # # are comment lines, and have no effect # ; are printable (in stdout) comments, and have no other effect # @ change the expect timeout value # ! Embedded Expect commands # ? If statement, use format ?cond?action::else_action # For more info see: http://expect-lite.sf.net/ @3 $mypass=mypass ; === Create the pass file using bash "here doc" >cat > $mypass <<'+++' >joe,1234 >jane,5678 >fred,abc! >+++ ; === now look at the file >cat $mypass ; === read password file into variable >cat $mypass | tr '\n' ' ' # don't capture prompt at end of line +$myfile=\n(.+)\$ $ ; === tease apart password file [ $tuple=$myfile ;;purple tuple is:$tuple # do string math $name=$tuple =$name/(\w+),.*/\1/ $pass=$tuple =$pass/.*,(\w+)/\1/ ;; === show name and pass: $name $pass >echo $name $pass ] > #*SHOW VARS >rm $mypass > expect-lite.proj/examples/test_pseudo_array.txt0000755000076400007640000000142612342711664022625 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # # Sample pseudo array variable script for blog # 27 May 2014 - Craig Miller # # display something everyone (except windows) has >ls -l /dev # initialize index variable $i=0 # initialize the first element in the pseudo array $dev$i=none # while loop testing the pseudo array value is captured [ $dev$i != __NO_STRING_CAPTURED__ +$i # capture the block device +$dev$i=\nb.*\d\d:\d\d (\w+) # expect the device to consume the output ? $dev$i != __NO_STRING_CAPTURED__ ? <$dev$i ] # set max devices captured $max=$i # initialize index variable $i=1 # while loop to check the devices in the pseudo array [ $i < $max # show the pseudo array value - the device >file /dev/$dev$i # check that it is a special device #pau expect-lite.proj/examples/fail.inc0000644000076400007640000000005512454577424017740 0ustar cvmillercvmiller# fail script ; === Set FAIL to 1 $FAIL=1 > expect-lite.proj/examples/mark_time_demo.txt0000755000076400007640000000064312532627714022050 0ustar cvmillercvmiller#!/usr/bin/env expect-lite # make this puppy run ;;; Demo to show time functions ;;; #include tcl functions ~tcl_functions.inc # initialize variables before using them with time functions $mytime1=0 $mytime2=0 !mark_time mytime1 >pwd !mark_time mytime2 >pwd !show_time mytime1 mydate # calculate elapsed time =$mytime2 - $mytime1 > ; == my date is:$mydate and time was:$mytime1 ; == elapsed time is: $mytime2 ms >