Introduction
Over the past year I have dedicated countless hours to building a unified terminal workflow that meshes tmux and reptyr with a parade of TUI libraries from rich / textual and PyTermGUI to curses. Why? Because while the command line is power, it is also a wall. The wall keeps potentially brilliant minds—who could advance open-source—on the wrong side of the divide. Wouldn’t it be a wonderful thing if it was possible to harness all the talent which exists on the other side? To be able to make things usable without neutering the depth power-users expect?
Discovery
On 14 Jan 2025 I disclosed a Broken Access Control flaw to Ultimate-Guitar. To automate exploitation I wrote EchoHeist – a shell script following the Regex → Replay → Redirect mantra. That project introduced me to fzf, the focal point of this article. You can read about the exploit here
EchoHeist – dynamic target selection via fzf
Ultimately I decided not to release EchoHeist publicly—too easy to abuse—so I filed a full disclosure report instead. Yet the experience lit a beacon: fzf was the missing interface glue for many of my scripts.
tmux – the Terminal Multiplexer
tmux logo
tmux drew me down a rabbit-hole of panes, windows and sessions. Programmatically, though, its dynamic index renumbering is maddening:
- pane indices shift every time you create or destroy one
- the same problem applies to windows and even sessions
- the only stable identifier is the pane title you assign manually
Experienced tmux hackers may shrug, but if you are writing automation the pain is real. I often fall back to raw shell ‘send-keys’ calls instead of libtmux.
A quick demonstration
The bash helper below spawns a pain_demo session, splits into four panes, shows their indices, kills one pane, adds a new pane, and lets you watch how indices reshuffle.
#!/usr/bin/env bash
# DtRH.net-pain_demo.sh – visualise tmux index chaos
SESSION="pain_demo"
tmux has-session -t "$SESSION" 2>/dev/null
if [[ $? -ne 0 ]]; then
echo "Creating new tmux session: $SESSION"
tmux new-session -d -s "$SESSION" -n pain_demo
send_cmd () { tmux send-keys -t "$SESSION:pain_demo.$1" "$2" C-m; }
# build 4-pane grid
tmux split-window -h -t "$SESSION:pain_demo.0"
tmux split-window -v -t "$SESSION:pain_demo.0"
tmux split-window -v -t "$SESSION:pain_demo.1"
for i in 0 1 2 3; do send_cmd $i "echo 'Initial Pane Index: $i'; bash"; done
sleep 10
echo "Removing pane 1…"
tmux kill-pane -t "$SESSION:pain_demo.1"
send_cmd 0 "clear; echo 'Updated Pane Index: 0'; bash"
send_cmd 2 "clear; echo 'Updated Pane Index: 1'; bash"
send_cmd 3 "clear; echo 'Updated Pane Index: 2'; bash"
sleep 10
echo "Adding a horizontal split from pane 0…"
tmux split-window -h -t "$SESSION:pain_demo.0"
# panes will be renumbered 0-3 automatically
for id in 0 1 2 3; do send_cmd $id "clear; echo 'Pane Index: $id'; bash"; done
sleep 10
fi
tmux attach -t "$SESSION"
What about reptyr?
reptyr re-parents an existing process to your current terminal—priceless when an SSH link might drop. The classic pattern:
- Start a long-running job over SSH by accident.
- Launch tmux, use reptyr to grab the process into a pane.
- Disconnect safely; the process keeps running inside tmux.
- Reattach later.
screen can play the same role on systems lacking tmux.
FZF – Fuzzy Finder
fzf filters massive lists at lightning speed, sparing beginners from complex regular expressions.
Simple safety wrapper:
ls -l Downloads/ | grep -i '.png' | fzf -m | xargs rm
Interactive file removal – choose files before 'rm' executes
Advanced fzf Implementations
1 · Continuous Log Viewer
Split tmux horizontally: top pane lists /var/log plus a live dmesg option via fzf; bottom pane tails the chosen log. Run until you ‘Ctrl-C’.
Live log navigation with fzf + tmux
Source: logview.py
2 · PSHijack
Browse running processes, preview details, then (optionally) steal the TTY with reptyr.
Process explorer + hijacker
Source: PSHijack.sh
3 · URLSex
Enter any URL, scrape every ‘href’, sort by extension, fuzzy-filter, then act on the selection.
Interactive link harvesting
Source: urlsex.py
Download Table
File |
Language |
Integrations |
Description |
logview.py |
Python |
tmux, fzf |
System log & event viewer |
PSHijack.sh |
Shell |
tmux, reptyr, fzf |
Dynamic process explorer / hijacker |
urlsex.py |
Python |
fzf |
Scrape links from a URL and act on selection |
References & Resources