Of course. Using pexpect with Python 2.7 is a common scenario, especially for maintaining legacy systems or automating older network devices. Here’s a comprehensive guide covering installation, basic usage, a practical example, and important considerations for Python 2.7.

What is pexpect?
pexpect is a pure Python module for spawning child applications and controlling them automatically. It's like a super-powered version of the subprocess module or os.system(), but it's designed for interactive sessions.
It's particularly useful for:
- Automating SSH/FTP/SFTP sessions.
- Configuring network devices (routers, switches, firewalls).
- Interacting with command-line tools that require user input (e.g.,
yum,apt-get,passwd). - Running scripts that require interactive confirmation.
Installation
First, you need to install pexpect. Since you're using Python 2.7, you'll need a version of pexpect that is compatible. pexpect version 4.8.0 was the last to officially support Python 2.7.
Using pip (Recommended):

# This will install the latest version compatible with Python 2.7 pip install pexpect==4.8.0
If you don't have pip for Python 2.7, you might need to install it first or use easy_install.
Using easy_install:
easy_install pexpect==4.8.0
Verification:
You can verify the installation by running a simple Python script:

# test_pexpect.py import pexpect print "pexpect version:", pexpect.__version__
Run it with your Python 2.7 interpreter:
python2.7 test_pexpect.py
You should see the version printed.
Core Concepts
pexpect works by "spawning" a process and then "expecting" specific patterns (strings or regular expressions) in its output. When it finds a match, it performs an action, like sending input or timing out.
The key components are:
pexpect.spawn(command, args=[], ...): This is the main function. It starts the command and returns aspawnobject, which you use to control the process.spawn.expect(patterns, timeout=-1): This is the heart ofpexpect. It waits for the child process to output any of the given patterns.patterns: Can be a string, a list of strings, or a compiled regex.timeout: How many seconds to wait before giving up. The default is-1, which means wait forever.- It returns the index of the pattern that matched (e.g.,
0for the first pattern in the list).
spawn.send(data): Sends the stringdatato the child process. It does not append a newline.spawn.sendline(data): Sends the stringdatato the child process, followed by a carriage return (\r). This is what you use most often for commands.spawn.isalive(): ReturnsTrueif the child process is still running.spawn.close(): Closes the connection to the child process and returns the exit status code.
Basic Example: Automating a Local ping Command
Let's start with a simple, non-interactive example to see the flow.
This script will ping google.com and look for the "bytes from" pattern, which indicates a successful reply.
# ping_example.py
import pexpect
import time
# The command we want to run
command = "ping -c 4 google.com" # -c 4 for 4 pings (Linux/macOS)
# On Windows, the command would be "ping -n 4 google.com"
print "Spawning command:", command
# Spawn the process. The `timeout` is for the expect() calls, not the command itself.
child = pexpect.spawn(command, timeout=10) # Wait up to 10 seconds for a pattern
# We expect one of two patterns:
# 1. A successful ping reply
# 2. A timeout (ping fails to find host)
# The order matters. It returns the index of the matched pattern.
index = child.expect([
"bytes from", # Pattern 0: Success
pexpect.TIMEOUT, # Pattern 1: Timeout
pexpect.EOF # Pattern 2: End of File (process ended)
])
if index == 0:
print "Ping successful!"
# Read the rest of the output until the process finishes
child.expect(pexpect.EOF)
elif index == 1:
print "ERROR: Ping timed out."
elif index == 2:
print "Process ended unexpectedly."
# Print the output from the child process
print "--- Full Output ---"
print child.before # All output before the last expect() match
print child.after # The output that caused the last expect() to match
print "-------------------"
# Ensure the process is closed
child.close()
print "Child process closed with exit code:", child.exitstatus
To run this:
python2.7 ping_example.py
Practical Example: Automating an SSH Session
This is where pexpect truly shines. This script will SSH into a remote server, run a command, and then log out.
Important: For this to work without a password prompt, you should have passwordless SSH set up using SSH keys. If not, you can use pexpect to handle the password prompt, but it's less secure.
# ssh_example.py
import pexpect
import time
# --- Configuration ---
host = 'your_server_ip'
username = 'your_username'
password = 'your_password' # Only needed if not using SSH keys
command_to_run = 'ls -l /home'
# --- Script ---
try:
# Construct the ssh command. The `-p 22` is optional if you use the default port.
# The `-o StrictHostKeyChecking=no` is to avoid the "Are you sure you want to continue connecting?" prompt.
# Use with caution in production.
ssh_command = 'ssh -o StrictHostKeyChecking=no %s@%s' % (username, host)
print "Spawning SSH command:", ssh_command
# Spawn the ssh process. Timeout is crucial for interactive prompts.
child = pexpect.spawn(ssh_command, timeout=5, encoding='utf-8')
# Expect the password prompt
# The pattern "password:" is case-insensitive by default.
child.expect('password:')
# Send the password
print "Sending password..."
child.sendline(password)
# Expect the shell prompt. This is the trickiest part.
# The prompt varies greatly between systems (e.g., 'username@hostname:~$ ', '# ').
# You need to find a reliable pattern for your target machine.
# We'll use a common pattern: a word, '@', a word, ':', a path, and a special character.
# The '$ ' is for a regular user. For root, it might be '# '.
# We add a timeout in case the login fails.
child.expect(r'[\$#]\s') # Expects a '$' or '#' followed by a space
print "SSH login successful."
# Send the command to run
print "Running command:", command_to_run
child.sendline(command_to_run)
# Expect the command to finish and return to the prompt
child.expect(r'[\$#]\s')
print "Command finished."
# Print the output of the command
# The output is in `child.before`, but we need to be careful about what's in it.
# It includes the command we sent and its output.
print "--- Command Output ---"
# Split the output by newlines and take everything after the command we sent
lines = child.before.splitlines()
# The command we sent is the first line of the output
sent_command_line = lines[0]
# The actual output starts from the second line
output = '\n'.join(lines[1:])
print output
print "----------------------"
# Log out
print "Logging out..."
child.sendline('exit')
child.expect(pexpect.EOF) # Wait for the ssh process to terminate
except pexpect.TIMEOUT:
print "ERROR: Timeout occurred."
except pexpect.EOF:
print "ERROR: End of File. The process may have exited unexpectedly."
print "Buffer:", child.before
except Exception as e:
print "An unexpected error occurred:", e
finally:
if child.isalive():
child.close()
print "Script finished."
Important Considerations for Python 2.7
-
String Encoding (
.before,.after):- In Python 2.7, strings are byte-strings by default. The output from a command might not be in ASCII.
- Problem: If you try to print
child.beforeand it contains non-ASCII characters (like in alscommand with accented characters), you might get aUnicodeDecodeError. - Solution: The
pexpectspawnobject has anencodingparameter. Setting it to'utf-8'(or another appropriate encoding) will makechild.beforeandchild.afterreturn Unicode strings, which are much safer to work with.child = pexpect.spawn(command, timeout=10, encoding='utf-8')
-
Security: Storing Passwords:
- Never hardcode passwords in your script. This is a major security risk.
- Use environment variables, a configuration file with restricted permissions, or a secrets management tool.
-
Finding the Right Prompt:
- The biggest challenge with interactive scripts is reliably detecting the command prompt. It can change based on your current directory, the user, or even the terminal's state.
- Debugging Tip: If
expect()is timing out, it means the pattern you're looking for wasn't found. Printchild.beforeto see what the process actually sent you. This will help you craft a better regular expression.
-
Python 2.7 is End-of-Life (EOL):
- Python 2.7 reached its official end-of-life on January 1, 2025. It no longer receives security updates or bug fixes.
- Strong Recommendation: The long-term goal should be to migrate your code to Python 3. The
pexpectlibrary is fully compatible with Python 3, and the syntax is largely the same. The main work will be in handling strings and print statements correctly for Python 3.
