No description
  • Rust 60.9%
  • Python 39.1%
Find a file
2026-05-20 09:12:25 +00:00
assets Add README logo 2026-05-20 10:39:55 +02:00
examples Fix README screenshot table borders 2026-05-20 10:07:35 +02:00
legacy Add unit tests 2026-05-20 04:22:41 +02:00
src Add unit tests 2026-05-20 04:22:41 +02:00
.gitignore Add legacy Python implementation 2026-05-20 04:15:04 +02:00
Cargo.lock Initial unpipe implementation 2026-05-20 04:11:20 +02:00
Cargo.toml Initial unpipe implementation 2026-05-20 04:11:20 +02:00
README.md docs: clarify bash runtime requirement 2026-05-20 11:10:07 +02:00
requirements-unpipe.md docs: clarify bash runtime requirement 2026-05-20 11:10:07 +02:00

unpipe - pipe command output like it was never piped

unpipe logo

unpipe lets you capture, pipe, page, or watch the rich output you normally only get on screen: colors, tables, progress bars, box drawing, and other ANSI rendering included.

Internally, unpipe uses a private detached tmux server and tmux capture-pane.

What It's For

Some commands look great on screen but lose their layout, colors, or useful view as soon as you pipe them. unpipe keeps that screen-style output intact and still lets you send it wherever you want.

unpipe --watch is a color-preserving watch alternative: it keeps ANSI output intact, lets you scroll through long results, and keeps your scroll position while the command refreshes.

unpipe watch mode running cargo test

The same capture path works for one-shot output and for piping rendered terminal output into another tool:

unpipe capturing cargo test and git log output unpipe output from git log piped into bat

The images below use synthetic terminal-aware fixtures from examples/. They show the same modes with stable, deliberately simple data:

unpipe watch mode

unpipe capturing terminal-aware output unpipe output piped into bat

Examples

Render a terminal-aware command and print the captured output:

unpipe examples/tty-dashboard.sh

Pipe terminal-rendered output into bat:

unpipe examples/wide-report.sh | bat

When stdout is piped, unpipe applies a default -10 width compatibility offset so tools with side gutters, such as bat, do not wrap full-width table output. Disable that when the downstream command should receive the full-width capture:

unpipe --no-compat -- examples/wide-report.sh | cat

Control capture width explicitly:

unpipe --width 120 -- examples/wide-report.sh
unpipe --width-offset -14 -- examples/wide-report.sh | bat

Watch and rerender output without watch stripping or misinterpreting ANSI:

unpipe --watch 0.5 -- examples/live-status.sh

Watch Keys

q, Ctrl-C       quit
Up/k, Down/j   scroll one line
PgUp/PgDn      scroll one page
Home/g         top
End/G          bottom, and follow bottom on refresh
r              rerender now

Environment

UNPIPE_WIDTH          pane width; default: current terminal columns
UNPIPE_WIDTH_OFFSET   signed width offset; piped stdout defaults to -10 when unset
UNPIPE_HEIGHT         pane height; default: current terminal rows, or rows - 1 in watch mode
UNPIPE_HISTORY        tmux scrollback lines; default: 200000
UNPIPE_KEEPALIVE      seconds to keep pane alive after command exit; default: 3600
UNPIPE_TMUX           tmux binary; default: tmux
UNPIPE_PLAIN          strip rendered ANSI attributes when set to 1/yes/true/on

Build

cargo build --release

Install locally:

install -m 755 target/release/unpipe ~/.local/bin/unpipe

Legacy Python Version

The Rust binary is the primary implementation. The previous Python implementation is included as a legacy reference:

legacy/unpipe.py examples/tty-dashboard.sh
legacy/unpipe.py --watch 0.5 -- examples/live-status.sh

It uses the same command-line shape and UNPIPE_* environment variables, but new development should target the Rust implementation.

Tests

Run the Rust unit tests:

cargo test

Run the legacy Python tests:

python3 -m unittest legacy/test_unpipe.py

Runtime Requirements

  • tmux
  • stty
  • date
  • chmod
  • bash available on PATH

No Cargo dependencies are used.