pexpect
Python library for controlling and automating interactive terminal applications — spawns child processes and interacts with them via pseudo-terminal (pty), similar to Unix expect. pexpect features: pexpect.spawn() for process spawning, expect() with string/regex/EOF/TIMEOUT patterns, sendline()/send() for input, before/after attributes for matched text, interact() for handoff to user, pexpect.run() for simple one-shot execution, pxssh class for SSH automation, timeout and maxread configuration, logfile for interaction logging, and fdpexpect for existing file descriptors. Essential for automating CLI tools that don't support piped stdin/stdout.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
CRITICAL: pexpect is frequently used to automate SSH password entry — this embeds passwords in Python source code or process arguments visible in ps output. Always prefer SSH key authentication over pexpect password automation. Process arguments may be visible to other users via ps aux. Use environment variables or secret managers for credentials passed to spawned processes.
⚡ Reliability
Best When
Automating interactive terminal applications that check if stdin is a TTY and behave differently with pipes — SSH clients, Python REPL, sudo, sftp, interactive database CLIs — where subprocess cannot work.
Avoid When
The process supports non-interactive piped I/O (use subprocess), you're on Windows, or you need async process control.
Use Cases
- • Agent SSH automation — import pexpect; child = pexpect.spawn('ssh user@host'); child.expect(['password:', pexpect.EOF]); child.sendline('mypassword'); child.expect('\$'); child.sendline('ls -la'); child.expect('\$'); output = child.before.decode() — automate interactive SSH login; agent infrastructure automation handles password prompts that break subprocess.run(); captures command output between prompts
- • Agent interactive CLI control — child = pexpect.spawn('python3 -i'); child.expect('>>> '); child.sendline('import sys; sys.version'); child.expect('>>> '); version = child.before.decode().strip() — control interactive Python REPL; agent test framework drives interactive interpreters; works for any CLI tool that reads from TTY
- • Agent process with pxssh — from pexpect import pxssh; s = pxssh.pxssh(); s.login('hostname', 'username', 'password'); s.sendline('uptime'); s.prompt(); print(s.before.decode()); s.logout() — high-level SSH automation; agent remote management runs commands on multiple hosts; pxssh handles SSH prompt detection better than raw spawn
- • Agent expect with timeout — child = pexpect.spawn('slow_tool', timeout=30); index = child.expect(['success', 'error', pexpect.TIMEOUT, pexpect.EOF]); if index == 2: handle_timeout(); elif index == 3: handle_eof() — pattern list returns index of matched pattern; agent handles multiple possible outcomes; TIMEOUT and EOF are special sentinels not strings
- • Agent interaction logging — child = pexpect.spawn('interactive_tool', logfile=open('session.log', 'wb')); child.expect('prompt>'); child.sendline('command') — all I/O logged to file; agent audit trail records complete terminal session for debugging; logfile receives raw bytes including ANSI escape codes
Not For
- • Non-interactive processes — pexpect uses PTY overhead; for processes that support piped I/O use subprocess.run() or subprocess.Popen() which are simpler and faster
- • Windows — pexpect.spawn() requires Unix PTY; use wexpect or winpexpect on Windows; pexpect.run() works on Windows but without pty features
- • Async code — pexpect is synchronous blocking; for async process control use asyncio.create_subprocess_exec() or anyio.run_process()
Interface
Authentication
No auth — pexpect itself has no auth. SSH automation via pxssh passes credentials to SSH process. Never hardcode passwords in production — use SSH keys instead of pexpect password automation.
Pricing
pexpect is ISC licensed. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ expect() raises TIMEOUT not returns it — child.expect('prompt') raises pexpect.TIMEOUT after timeout seconds; agent code must use try/except pexpect.TIMEOUT or pass TIMEOUT in pattern list: child.expect(['prompt', pexpect.TIMEOUT]); forgetting to handle timeout leaves agent hanging forever without error output
- ⚠ before attribute contains bytes not string — child.before and child.after are bytes objects; agent code doing child.before.split('\n') fails with TypeError; must decode: child.before.decode('utf-8', errors='replace'); ANSI escape codes in before require stripping: re.sub(r'\x1b\[[0-9;]*m', '', text)
- ⚠ PTY echoes sent input in before — when agent sends 'ls -la', the expect() match includes echoed 'ls -la' in before; agent parsing before for command output receives the command itself followed by output; skip first line or use sendline() + expect() + before[before.find('\n'):] to skip echo
- ⚠ spawn() requires full path on some systems — pexpect.spawn('ssh') may fail if ssh not in PATH; use pexpect.spawn('/usr/bin/ssh') or pexpect.which('ssh') to get full path; agent code relying on PATH works in interactive shells but may fail in cron/systemd where PATH is minimal
- ⚠ Windows not supported for spawn() — pexpect.spawn() raises ImportError on Windows (no pty module); agent cross-platform code must check: if sys.platform == 'win32': use subprocess else: use pexpect; pexpect.run() works on Windows but without TTY features that make pexpect necessary
- ⚠ interact() blocks until EOF — child.interact() hands control to user and blocks until process exits; agent code calling interact() inside automation flow will block indefinitely if no human is present; only use interact() for debugging or hybrid human/agent workflows where human takes over at specific point
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for pexpect.
Scores are editorial opinions as of 2026-03-06.