Capture pane output
The other half of Attach and send keys: reading what a pane printed, and — since tmux accepts a command before the shell running it has necessarily finished (see Sending keys) — waiting for the right moment to read rather than reading immediately or sleeping a guessed amount. Capturing output is the guide-level discussion of why each pattern below exists; this page is the sourced code behind it — see the table at the end for exactly which file each block came from and how it’s checked.
Read what’s on screenLink to section
let lines = pane.capture().await?; for line in lines.iter().filter(|line| !line.as_bytes().is_empty()) { println!(" | {}", line.to_string_lossy()); }No checked .NET example calls the ordinary Pane.CaptureAsync by itself
outside a wait — the README’s own read is the block under “Wait for text
instead of guessing a delay” below, and the separate Psmux surface has its
own CaptureAsync for that different transport
(examples/LibTmux.Examples/Snippets/Psmux.cs).
Wait for text instead of guessing a delayLink to section
Python’s checked wait is wait_for, tmux’s own signal channel, rather than
a helper that scrapes pane text for a pattern — no checked helper that
waits on pane text was found in the source for this page.
Session.OpenNotifications streams what tmux does as it happens rather than
polling — tmux pushes each change instead of a poll guessing how often to
ask. tmuxtest.WaitForText (see
Testing with libtmux) is the equivalent
built specifically for tests.
// From crates/libtmux/examples/scratch.rs, the wait_for_text call — shown in full on Attach and send keys.match pane.wait_for_text("hello", Duration::from_secs(5)).await? { PaneWait::Arrived => println!(" the pane printed it"), other => println!(" gave up: {other:?}"),}Rust’s wait_for_text looks before it sleeps, joins wrapped lines so a
needle spanning a wrap still matches, and returns PaneWait::Dead rather
than hanging forever if the pane’s process ends first.
Attaching a ControlClient is what makes tmux push %output at all — a
client that never attaches only ever hears command replies.
TmuxWait.UntilAsync polls a read against a predicate rather than sleeping
a fixed amount.
C++ has no checked snippet that waits on pane text. Server::wait_for(channel, timeout), in include/libtmux/server.hpp, uses tmux’s own wait-for signal
instead of scraping output, and its doc comment explains why that is the
safer choice when the command you are waiting on can be made to announce
itself: “a server that dies under a waiter makes tmux exit zero, which is
indistinguishable from being signalled … this reports that as a failure
instead.”
waitForOutput takes patterns for both success and failure, so a process
that fails fast is discovered immediately rather than by timing out.
Where this comes fromLink to section
| Port | Source | In this page | Checked by |
|---|---|---|---|
| Python | src/libtmux/pane.py (capture_pane), src/libtmux/server.py (wait_for) docstrings | hand-quoted | pytest runs every >>> doctest against a real, isolated tmux session on every test run |
| TypeScript | examples/capture/capture.ts (read), examples/agent/agent.ts (wait) | read whole from each file | both run against real tmux by bun test examples; agent.ts is additionally mirrored into README.md under a <!-- runs: ... --> marker checked by scripts/check-doc-runnable.ts |
| Go | examples/quickstart/main.go (read, already shown whole on the previous page), examples/control-mode-subscribe/main.go (wait) | read: hand-quoted; wait: read whole from the file | both run against real tmux as TestQuickstart / TestControlModeSubscribe; the wait file’s docs:watching region is additionally mirrored into README.md by go generate ./tmux |
| Rust | crates/libtmux/examples/scratch.rs, already shown whole on the previous page | hand-quoted excerpts of the same file | run to completion against a throwaway tmux by scripts/run-examples.sh, which CI runs |
| Java | root README.md Quickstart (read), examples/src/main/java/io/github/libtmux/examples/WatchPaneOutput.java (wait) | read: hand-quoted; wait: read whole from the file | every README fence is compiled and run against real tmux by docs-tests; WatchPaneOutput is additionally run by the examples module’s ExamplesRunTest |
| .NET | root README.md, “Running something, and reading it back” | hand-quoted | one of the csharp run blocks compiled and run against real tmux by ReadmeExampleTests |
| C++ | examples/05-readme.cpp capture region (read); include/libtmux/server.hpp doc comment (wait, no fence) | hand-quoted | the capture region is quoted verbatim into README.md and checked by tools/docs/check_readme.py; the whole file is built and run by CTest |
| Swift | Examples/Sources/ExampleCode/Changing.swift (read, already shown whole on the previous page), Waiting.swift (wait) | read: hand-quoted excerpt; wait: read whole from the file | both matched against the README by Scripts/check_examples.py and run by swift test --package-path Examples |
Go, Rust, and Swift each reuse a file already shown in full on Attach and send keys: rather than dump the same file a second time, this page quotes just the relevant lines by hand, with a comment naming the source, and points back at the full listing there.