Pane Interaction¶
libtmux provides powerful methods for interacting with tmux panes programmatically. This is especially useful for automation, testing, and orchestrating terminal-based workflows.
Open two terminals:
Terminal one: start tmux in a separate terminal:
$ tmux
Terminal two, python or ptpython if you have it:
$ python
Sending Commands¶
The send_keys() method sends text to a pane, optionally pressing
Enter to execute it.
Basic command execution¶
>>> pane = window.split(shell='sh')
>>> pane.send_keys('echo "Hello from libtmux"')
>>> import time; time.sleep(0.1) # Allow command to execute
>>> output = pane.capture_pane()
>>> 'Hello from libtmux' in '\\n'.join(output)
True
Send without pressing Enter¶
Use enter=False to type text without executing:
>>> pane.send_keys('echo "waiting"', enter=False)
>>> # Text is typed but not executed
>>> output = pane.capture_pane()
>>> 'waiting' in '\\n'.join(output)
True
Press Enter separately with enter():
>>> import time
>>> # First type something without pressing Enter
>>> pane.send_keys('echo "execute me"', enter=False)
>>> pane.enter()
Pane(%... Window(@... ..., Session($... ...)))
>>> time.sleep(0.2)
>>> output = pane.capture_pane()
>>> 'execute me' in '\\n'.join(output)
True
Literal mode for special characters¶
Use literal=True to send special characters without interpretation:
>>> import time
>>> pane.send_keys('echo "Tab:\\tNewline:\\n"', literal=True)
>>> time.sleep(0.1)
Suppress shell history¶
Use suppress_history=True to prepend a space (prevents command from being
saved in shell history):
>>> import time
>>> pane.send_keys('echo "secret command"', suppress_history=True)
>>> time.sleep(0.1)
Capturing Output¶
The capture_pane() method captures text from a pane’s buffer.
Basic capture¶
>>> import time
>>> pane.send_keys('echo "Line 1"; echo "Line 2"; echo "Line 3"')
>>> time.sleep(0.1)
>>> output = pane.capture_pane()
>>> isinstance(output, list)
True
>>> any('Line 2' in line for line in output)
True
Capture with line ranges¶
Capture specific line ranges using start and end parameters:
>>> # Capture last 5 lines of visible pane
>>> recent = pane.capture_pane(start=-5, end='-')
>>> isinstance(recent, list)
True
>>> # Capture from start of history to current
>>> full_history = pane.capture_pane(start='-', end='-')
>>> len(full_history) >= 0
True
Waiting for Output¶
A common pattern in automation is waiting for a command to complete.
Polling for completion marker¶
>>> import time
>>> pane.send_keys('sleep 0.2; echo "TASK_COMPLETE"')
>>> # Poll for completion
>>> for _ in range(30):
... output = pane.capture_pane()
... if 'TASK_COMPLETE' in '\\n'.join(output):
... break
... time.sleep(0.1)
>>> 'TASK_COMPLETE' in '\\n'.join(output)
True
Helper function for waiting¶
>>> import time
>>> def wait_for_text(pane, text, timeout=5.0):
... """Wait for text to appear in pane output."""
... start = time.time()
... while time.time() - start < timeout:
... output = pane.capture_pane()
... if text in '\\n'.join(output):
... return True
... time.sleep(0.1)
... return False
>>> pane.send_keys('echo "READY"')
>>> wait_for_text(pane, 'READY', timeout=2.0)
True
Querying Pane State¶
The display_message() method queries tmux format variables.
Get pane dimensions¶
>>> width = pane.display_message('#{pane_width}', get_text=True)
>>> isinstance(width, list) and len(width) > 0
True
>>> height = pane.display_message('#{pane_height}', get_text=True)
>>> isinstance(height, list) and len(height) > 0
True
Get pane information¶
>>> # Current working directory
>>> cwd = pane.display_message('#{pane_current_path}', get_text=True)
>>> isinstance(cwd, list)
True
>>> # Pane ID
>>> pane_id = pane.display_message('#{pane_id}', get_text=True)
>>> pane_id[0].startswith('%')
True
Common format variables¶
Variable |
Description |
|---|---|
|
Pane width in characters |
|
Pane height in characters |
|
Current working directory |
|
PID of the pane’s shell |
|
Unique pane ID (e.g., |
|
Pane index in window |
Resizing Panes¶
The resize() method adjusts pane dimensions.
Resize by specific dimensions¶
>>> # Make pane larger
>>> pane.resize(height=20, width=80)
Pane(%... Window(@... ..., Session($... ...)))
Resize by adjustment¶
>>> from libtmux.constants import ResizeAdjustmentDirection
>>> # Increase height by 5 rows
>>> pane.resize(adjustment_direction=ResizeAdjustmentDirection.Up, adjustment=5)
Pane(%... Window(@... ..., Session($... ...)))
>>> # Decrease width by 10 columns
>>> pane.resize(adjustment_direction=ResizeAdjustmentDirection.Left, adjustment=10)
Pane(%... Window(@... ..., Session($... ...)))
Zoom toggle¶
>>> # Zoom pane to fill window
>>> pane.resize(zoom=True)
Pane(%... Window(@... ..., Session($... ...)))
>>> # Unzoom
>>> pane.resize(zoom=True)
Pane(%... Window(@... ..., Session($... ...)))
Clearing the Pane¶
The clear() method clears the pane’s screen:
>>> pane.clear()
Pane(%... Window(@... ..., Session($... ...)))
Killing Panes¶
The kill() method destroys a pane:
>>> # Create a temporary pane
>>> temp_pane = pane.split()
>>> temp_pane in window.panes
True
>>> # Kill it
>>> temp_pane.kill()
>>> temp_pane not in window.panes
True
Kill all except current¶
>>> # Setup: create multiple panes
>>> pane.window.resize(height=60, width=120)
Window(@... ...)
>>> keep_pane = pane.split()
>>> extra1 = pane.split()
>>> extra2 = pane.split()
>>> # Kill all except keep_pane
>>> keep_pane.kill(all_except=True)
>>> keep_pane in window.panes
True
>>> extra1 not in window.panes
True
>>> extra2 not in window.panes
True
>>> # Cleanup
>>> keep_pane.kill()
Practical Recipes¶
Recipe: Run command and capture output¶
>>> import time
>>> def run_and_capture(pane, command, marker='__DONE__', timeout=5.0):
... """Run a command and return its output."""
... pane.send_keys(f'{command}; echo {marker}')
... start = time.time()
... while time.time() - start < timeout:
... output = pane.capture_pane()
... output_str = '\\n'.join(output)
... if marker in output_str:
... return output # Return all captured output
... time.sleep(0.1)
... raise TimeoutError(f'Command did not complete within {timeout}s')
>>> result = run_and_capture(pane, 'echo "captured text"', timeout=2.0)
>>> 'captured text' in '\\n'.join(result)
True
Recipe: Check for error patterns¶
>>> import time
>>> def check_for_errors(pane, error_patterns=None):
... """Check pane output for error patterns."""
... if error_patterns is None:
... error_patterns = ['error:', 'Error:', 'ERROR', 'failed', 'FAILED']
... output = '\\n'.join(pane.capture_pane())
... for pattern in error_patterns:
... if pattern in output:
... return True
... return False
>>> pane.send_keys('echo "All good"')
>>> time.sleep(0.1)
>>> check_for_errors(pane)
False
See also
API Reference for the full API reference
Panefor all pane methodsAutomation Patterns for advanced orchestration patterns