A detailed description of Linux expect usage
I. Overview
Through the shell we can achieve simple control flow functions, such as: cycle, judgment and so on. But for situations where interaction needs to be done manually, we may sometimes need to implement interactions with interactive programs such as Telnet Server. And expect is used to implement this function of the tool.
Expect is a free programming language that enables automated and interactive tasks to communicate without the need for human intervention. Expect's author, Don Libes, began writing Expect in 1990 with the following definition of Expect: Expect is a software suite for automatic interactivity (Expect [is a] software suite for automating Interactive tools). Using it, the system administrator can create scripts to provide input to commands or programs that are expected to be entered from the terminal (terminal), which in general need to be entered manually. Expect can simulate the input provided by the standard input to the program according to the program's prompt to realize the interactive program execution. Can even implement simple BBS chat robot. :)
Expect is a continuous development, with the passage of time, its function becomes more and more powerful, has become the system administrator's a powerful assistant. Expect requires the support of the TCL programming language and TCL must first be installed to run expect on the system.
Second, expect working principle
At its simplest level, expect works like a generalized chat scripting tool. The chat script was first used within the UUCP network to automate specific logon sessions between computers that needed to establish a connection.
The chat script consists of a series of expect-send pairs: The expect waits for output to output a specific character, usually a prompt, and then sends a specific response. For example, the following chat script implementation waits for the standard output to appear in login: string, then sends somebody as the user name, and then waits for password: Prompt and emits a response sillyme.
Reference: Login:somebody Password:sillyme
This script is used to implement a login process and login with a specific user name and password.
Expect the simplest script mode of operation is essentially the same as the chat script working mode.
Example:
1. Realization function
Below we analyze a script that responds to the CHSH command. Let's look at the format of this interactive command first. Let's say we want to change the login script for the user Chavez, which requires the following commands to be implemented:
Ref: # Chsh Chavez
Changing the login shell for Chavez
Enter the new value, or press return for the default
Login Shell [/bin/bash]:/bin/tcsh
#
You can see that the command first outputs several line prompts and prompts for a new login shell for the user. We must enter the user's login shell after the prompt message or directly enter the login shell without modification.
2. The following is a expect script that can be used to implement the command automatically:
#!/usr/bin/expect
# Change a login shell to tcsh
Set user [lindex $argv 0]
Spawn Chsh $user
Expect "]:"
Send "/bin/tcsh"
Expect EOF
Exit
This simple script can explain the characteristics of many expect programs. As with other scripts, the first line specifies the command program used to execute the script, which is/usr/bin/expect. The first line of the program is used to get the execution parameters of the script (which is stored in the array $argv, starting from number No. 0 is the parameter) and saving it to the variable user.
The second parameter uses expect's Spawn command to start the session of the script and command, which starts with the CHSH command, which actually runs in the way of the derived subprocess.
Subsequent expect and send commands are used to implement the interactive process. The script waits for the output to appear in the first place]: string, once in the output CHSH output to the feature string (the general feature string is often waiting for the input of the last hint of the feature information). For other mismatched information, it is completely ignored. When the script gets the feature string, expect sends/bin/tcsh and a carriage return to the CHSH command. The final script waits for the command to exit (Chsh end), and once it receives the EOF character that identifies the child process has ended, the expect script exits the end.
3. Decide how to respond
Administrators often have the need to respond to a command in different ways, depending on the current situation. We can see from the following example that expect can achieve very complex conditional responses, but only by simply modifying the preprocessing scripts. The following example is an example of a more complex expect-send:
Expect-re "\[(. *)]:"
If {$expect _out (1,string)! = "/bin/tcsh"} {
Send "/bin/tcsh"}
Send ""
Expect EOF
In this example, the first expect command now uses the-re parameter, which indicates that the specified string is a regular expression, not a normal string. For the above example, look for an opening bracket character (which must be escaped three times, so there are three symbols because it is a special character for expect and regular expressions) followed by 0 or more characters, and finally a closing bracket character. Here. * represents one or more arbitrary characters that are stored in () because the matching results are stored in a variable to achieve subsequent access to the matching results.
When a match is found, check the string contained in [] to see if it is/bin/tcsh. If not, send/bin/tcsh to the CHSH command as input, or just send a carriage return if it is. This simple small example of different responses to specific situations illustrates the power of expect.
In a regular expression, you can include several parts in () and access them through the expect_out array. The sections are encoded from left to right in the expression, starting with 1 (0 containing the entire matching output). () A nesting situation may occur, in which case the encoding is carried out from the outermost to the outer layer.
4. Use timeout
The next expect example will explain the prompt function with the timeout function. This script prompts the user for input, and if there is no input within a given time, it will time out and return a default response. This script receives three parameters: the prompt string, the default response, and the time-out (in seconds).
#!/usr/bin/expect
# Prompt function with timeout and default.
Set prompt [lindex $argv 0]
Set def [lindex $ARGV 1]
Set Response $def
Set tout [lindex $argv 2]
The first part of the script is the first to get the running parameters and save them in an internal variable.
Send_tty "$prompt:"
Set timeout $tout
Expect "" {
Set Raw $expect _out (buffer)
# Remove Final carriage return
Set response [string TrimRight "$raw" ""]
}
If {"$response" = = "} {Set Response $def}
Send "$response
This is what the rest of the script does. You can see the Send_tty command for displaying the prompt string and a colon and a space on the terminal. The Set timeout command sets the wait response time for all subsequent expect commands to a timeout of $tout (the-l parameter is used to turn off any timeout setting).
The expect command then waits for the carriage return character to appear in the output. If a carriage return is obtained before the time-out, the SET command assigns the user's input to the face-changing raw. The following command removes the final return symbol of the user input and assigns it to the variable response.
Then, if the content in response is empty, the response value is set to the default value (if the user does not enter after the timeout or the user simply enters the carriage return character). The last Send command sends the value of the response variable plus the carriage return character to the standard output.
One interesting thing is that the script does not use the Spawn command. The expect script interacts with any process that invokes the script.
If the script is prompt, it can be used in any C-style shell.
% set a= ' Prompt "Enter an answer" silence 10 '
Enter an Answer:test
% echo Answer was "$a"
Answer was test
The timeout set by the prompt is 10 seconds. If the timeout is exceeded or the user simply enters a carriage return symbol, the echo command outputs
Answer was "silence"
5. A more complex example
Here we will discuss a more complex example of a expect script that uses some of the more complex control structures and many complex interaction processes. This example is used to implement sending the write command to any user, sending a message from a file or from a keyboard input.
#!/usr/bin/expect
# Write to multiple users from a prepared file
# or a message input interactively
If {$ARGC <2} {
Send_user "Usage: $argv 0 file user1 user2 ... "
Exit
}
The Send_user command is used to display standard output that uses help information to the parent process (typically the user's shell).
Set Nofile 0
# get filename via the TCL lindex function
Set file [lindex $argv 0]
if {$file = = "I"} {
Set Nofile 1
} else {
# Make sure message file exists
if {[File Isfile $file]!=1} {
Send_user "$argv 0:file $file not found."
Exit}}
This part implements the processing script startup parameter, which must be a file name that stores the message to be sent or an "I" command that represents the content to be sent using the interactive input.
The variable file is set to the value of the first parameter of the script, which is implemented by a TCL function lindex, which gets a specific element from the list/array. [] is used to implement the return value of the function Lindex as a parameter to the set command.
If the first parameter of the script is the lowercase "i", then the variable nofile is set to 1, otherwise the isfile of the parameter specified by the TCL function is called to verify the existence of the file, and the error exits if it does not exist.
You can see that the IF command is used here to implement the logical judgment function. This command is followed directly by the judgment condition, and executes the command within {} After judging the condition. If the IF condition is false, then the program block after else is run.
Set Procs {}
# Start Write processes
For {set I 1} {$i < $ARGC}
{INCR i} {
Spawn-noecho Write
[Lindex $argv $i]
Lappend procs $spawn _id
}
The last part uses the Spawn command to start the write process implementation to send a message to the user. This uses the for command to implement the loop control function, where the loop variable is first set to 1 and then incremented. The loop body is the contents of the last {}. Here we use the second and subsequent parameters of the script to spawn a write command and use each parameter as the user name to send the message. The Lappend command uses an internal variable that holds the process ID number of the process for each spawn $spawn_id constructs a list of process ID numbers in the variable procs.
If {$nofile ==0} {
SETMESG [Open "$file" "R"]
} else {
Send_user "Enter message,
Ending with ^d: "}
The final script opens the message file based on the value of the variable nofile or prompts the user to enter the message to be sent.
Set Timeout-1
While 1 {
If {$nofile ==0} {
If {[gets $mesg chars] = =-1} break
Set line "$chars"
} else {
Expect_user {
-re "" {}
EOF Break}
Set line $expect _out (buffer)}
foreach spawn_id $procs {
Send $line}
Sleep 1}
Exit
The above code shows how the actual message text is sent through an infinite loop while. The IF in the while loop determines how the message is obtained. In non-interactive mode, the next line of content is read from the message file, and the while loop ends when the file content ends. (The break command implements the terminating loop).
In interactive mode, the Expect_user command receives a message from the user, ends the input when the user enters Ctrl+d, and ends the loop at the same time. In both cases, the variable $line is used to hold the next line of message content. When it is a message file, the carriage return is appended to the end of the message.
The Foreach loop iterates through all the processes of the spawn, and the ID numbers of those processes are stored in the list variable $procs, respectively, to communicate with each process. The Send command makes up the loop body of foreach, sending a line of messages to the current write process. The last of the while loop is a sleep command, primarily for handling non-interactive mode situations, to ensure that messages are not sent too quickly to individual write processes. When the while loop exits, the expect script ends.
Other information:
Tips for flexible expect scripts under Linux
Expect use of the detailed