杰瑞科技汇

Python 2.7下pexpect如何使用?

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.

Python 2.7下pexpect如何使用?-图1
(图片来源网络,侵删)

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):

Python 2.7下pexpect如何使用?-图2
(图片来源网络,侵删)
# 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:

Python 2.7下pexpect如何使用?-图3
(图片来源网络,侵删)
# 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 a spawn object, which you use to control the process.
  • spawn.expect(patterns, timeout=-1): This is the heart of pexpect. 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., 0 for the first pattern in the list).
  • spawn.send(data): Sends the string data to the child process. It does not append a newline.
  • spawn.sendline(data): Sends the string data to the child process, followed by a carriage return (\r). This is what you use most often for commands.
  • spawn.isalive(): Returns True if 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

  1. 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.before and it contains non-ASCII characters (like in a ls command with accented characters), you might get a UnicodeDecodeError.
    • Solution: The pexpect spawn object has an encoding parameter. Setting it to 'utf-8' (or another appropriate encoding) will make child.before and child.after return Unicode strings, which are much safer to work with.
      child = pexpect.spawn(command, timeout=10, encoding='utf-8')
  2. 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.
  3. 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. Print child.before to see what the process actually sent you. This will help you craft a better regular expression.
  4. 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 pexpect library 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.
分享:
扫描分享到社交APP
上一篇
下一篇