// TEMPRS — TEMPORARY FILE STACK MANAGER

temprs v2.9.9 · Two binaries (tp + temprs) · Dual indexing (position + @name) · Null-byte master record · flock-protected, atomic writes · 5,635 tests

4,736 production Rust lines · 56,849 test Rust lines · 258 commits · 5 direct deps · zsh completion + man page

Report GitHub Issues
// Color scheme

>_TEMPRS — PUSH YOUR DATA. OWN YOUR TEMP FILES.

A stack-based temporary file manager for the shell. Pipe data into tp, get a numbered tempfile on top of a persistent stack. Address files by position (1, -1) or by tag (@mydata). Stack operations mirror Perl/Ruby arrays: push, pop, shift, unshift, move, swap, duplicate, reverse, sort. The master record is null-byte delimited, atomically renamed, and flock-protected so concurrent shells can't corrupt it. Both tp and temprs binaries are shipped from one Cargo target.

Quickstart

Install from crates.io or build from source. tp is the short alias; temprs is the long name. Both binaries are identical.

# install
cargo install temprs

# from source
git clone https://github.com/MenkeTechnologies/temprs
cd temprs && cargo build --release

# push stdin to a new tempfile on top of stack
echo "hello" | tp

# list the stack
tp -l

# read top of stack to stdout
tp | wc -l

# read tempfile at index 1
tp -o 1 | head -5

# tag a tempfile so you can recall it by name
ps aux | tp -w procs
tp -o procs | grep firefox

Full install + usage live in the README; the man page is shipped at man/temprs.1.


Stack architecture

Tempfiles are ordered in a persistent stack. Top of stack is the newest entry. Indices are 1-based ascending from the bottom; negative indices count from the top (-1 = top, -stack_size = bottom). Index 0 is always invalid.

┌─────────────────────────────────────┐ │ INDEX N ▓▓ TOP OF STACK (newest)│ │ INDEX N-1 ▓▓ ... │ │ INDEX 2 ▓▓ ... │ │ INDEX 1 ▓▓ BOTTOM OF STACK │ └─────────────────────────────────────┘

Files live in $TMPDIR/temprs/ (override with TEMPRS_DIR). The master record (master) maps index → filename → optional tag. Stack position is reconstructed from the master on every invocation, so multiple shells share one canonical view.


Dual indexing — by position or by @name

Every operation that takes an INDEX also accepts a tag name. Resolution order: numeric parse first, then tag lookup. Names are unique across the stack and travel with their files through every stack mutation (move, swap, duplicate). Names render with a @ prefix in listings.

# tag on creation
ps aux | tp -w procs

# tag on existing file (rename)
tp -R 1 newname
tp -R procs procs2

# use the tag anywhere INDEX is accepted
tp -o procs
tp -r procs
tp -A procs < more.txt
tp -M procs 1
tp -S procs other
tp -x procs
tp --head procs 10
tp --replace procs old new

Operations — full surface

I/O

tp (push stdin), tp FILE (load file), tp -i N (write into N), tp -o N (read N to stdout), tp -v (verbose = also write to stdout), tp -A N (append to N).

Stack mutation

-p pop, -u unshift, -s shift, -a N insert at N, -r N remove, -M src dst move, -S a b swap, -x N duplicate to top.

Bulk

--rev reverse the stack, --sort name|size|mtime sort, -c purge all, --expire HOURS purge by mtime (fractional hours OK: 0.5).

Listing

-l list, -L list with contents, -n numbered, -N numbered with contents, -k count, -d show temprs directory, -m show master file.

Inspect

-I N metadata, --head N [LINES], --tail N [LINES], --wc N, --size N, --path N (raw filesystem path for shell substitution).

Search & transform

-g PATTERN grep across all tempfiles (exit 0/1), --replace N PAT REPL find-and-replace in place (prints replacement count).

Combine

-C a b c concat tempfiles to stdout in order (indices and names freely mixed), -D a b unified diff of two tempfiles.

Tagging

-w NAME tag a new tempfile on creation, -R src NAME rename a tag, names render as @name in listings.

Editor

-e N open in $EDITOR (falls back to vi), works with -1 for top-of-stack.


Flag reference

The same flag set is bound under both binaries. Long forms shown where they exist; tp -h prints the cyberpunk banner + grouped help.

FlagArgumentBehavior
-i, --inputINDEXWrite stdin into tempfile at INDEX
-o, --outputINDEXRead tempfile at INDEX to stdout
-a, --addINDEX [FILE]Insert new tempfile at INDEX (from stdin or FILE)
-r, --removeINDEXRemove tempfile at INDEX
-p, --pop Pop top of stack
-u, --unshift Push to bottom (stdin in, no stdout)
-s, --shift Shift from bottom
-A, --appendINDEXAppend stdin to tempfile at INDEX
-v, --verbose Also echo data to stdout on write
-w, --write-nameNAMETag new tempfile with NAME
-R, --renameSRC NAMERename tag (SRC = index or current name)
-l, --list List stack
-L List stack with contents
-n List stack numbered
-N List stack numbered with contents
-k, --count Print stack size
-d, --dir Print temprs directory
-m, --master Print master record path
-c, --clear Purge all tempfiles
--expireHOURSPurge tempfiles older than HOURS (fractional OK)
-e, --editINDEXOpen INDEX in $EDITOR (fallback vi)
-I, --infoINDEXShow metadata for INDEX
--headINDEX [LINES]Head of INDEX (default 10)
--tailINDEX [LINES]Tail of INDEX (default 10)
--wcINDEXLine count of INDEX
--sizeINDEXByte size of INDEX
--pathINDEXFilesystem path of INDEX (for cat "$(tp --path 1)")
-g, --grepPATTERNGrep all tempfiles (exit 0 on match, 1 on none)
--replaceINDEX PAT REPLReplace PAT with REPL in INDEX, print replacement count
-C, --concatINDEX...Concatenate listed tempfiles to stdout
-D, --diffA BUnified diff of two tempfiles
-M, --moveSRC DSTMove tempfile from SRC to DST position
-S, --swapA BSwap two tempfiles
-x, --dupINDEXDuplicate INDEX onto top of stack
--rev Reverse the entire stack
--sortname|size|mtimeSort the stack

Data integrity

The master record is the single source of truth for the stack. Three layered protections prevent corruption under concurrent access:

  • Null-byte delimited format — fields separated by \0, records by \0\0. Filenames containing newlines, tabs, spaces, or any other shell-metacharacters parse correctly. No quoting, no escaping.
  • Atomic writes — the master is written to a sibling temp file and renamed into place. A crash mid-write leaves the previous master intact; readers never see a partial record.
  • Exclusive file lockingfs2::FileExt::lock_exclusive wraps every read-modify-write. Two shells racing on the same stack serialize cleanly; neither sees a half-mutated state.
  • Auto-recovery — corrupt or empty records (e.g. from an aborted external edit) are silently skipped on read and cleaned up on the next write.

Environment

VariableEffect
TEMPRS_DIROverride the tempfile + master record directory. Default: $TMPDIR/temprs (or /tmp/temprs if $TMPDIR is unset).
EDITORUsed by tp -e INDEX. Falls back to vi.

Shell integration

A zsh completion lives at completions/_temprs and dynamically resolves stack indices, file names, and @name tags — tab-completion sees the current stack, not a static word list.

# install into your fpath
cp completions/_temprs /usr/local/share/zsh/site-functions/_tp

# or extend fpath in .zshrc
fpath=(/path/to/temprs/completions $fpath)
autoload -Uz compinit && compinit

A groff man page is shipped at man/temprs.1 — install to $MANPATH/man1/ for man tp.


Pipeline examples

# capture, transform, recall
ps aux | tp -w procs
tp -o procs | awk '$3 > 5'

# diff two captures
curl -s api/v1/state | tp -w before
make deploy
curl -s api/v1/state | tp -w after
tp -D before after

# build a working set, then dump it
grep -r TODO src | tp -w todos
grep -r FIXME src | tp -w fixmes
tp -C todos fixmes | sort -u

# edit a captured payload, then re-emit
curl -s config.json | tp -w cfg
tp -e cfg
tp -o cfg | curl -X PUT --data-binary @- api/v1/config

# expiry & housekeeping
tp --expire 24    # drop anything older than a day
tp --expire 0.5   # drop anything older than 30 minutes
tp -c             # drop everything

Development & CI

The repository ships with a GitHub Actions workflow at .github/workflows/ci.yml that runs cargo check, the full cargo test suite (5,635 tests — 5,082 unit + 553 integration), cargo fmt --check, cargo clippy, cargo doc, and a release build on every push to main and on every pull request. Criterion benchmarks live under benches/benchmarks.rs (cargo bench).

For more detail on architecture, test breakdown, and module-level statistics, see the engineering report.