teip: Because You Shouldn't Have to Rewrite awk in Order to Base64-Encode Column 3

2026-08-26

You have a stream of lines. You want to transform one column, one regex match, or one byte range per line with some existing command — base64, dig, jq, whatever — and leave the rest untouched. The classical answers are all bad:

teip (by Yasuhiro Yamada, MIT-licensed Rust binary, in nixpkgs / brew / AUR / cargo install teip) is the tool for exactly this shape of problem. It masks the parts of stdin you don't want touched, streams only the masked substrings to a subcommand that runs once, then splices the transformed output back into the original positions verbatim.

# Uppercase only the 3rd whitespace field
$ echo "alpha bravo charlie delta" | teip -f 3 -- tr a-z A-Z
alpha bravo CHARLIE delta

# Reverse-lookup only the IPs in access-log lines
$ cat access.log | teip -og '\d+\.\d+\.\d+\.\d+' -- dig +short -x
router.lan. - - [26/Aug/2026:14:03:11] "GET / HTTP/1.1"

# jq only the JSON blob embedded in each syslog line
$ journalctl -u myapp | teip -og '\{.*\}' -- jq -c '.request_id'

# Base64-decode column 4 of a CSV (with proper quoting)
$ teip --csv -f 4 -- base64 -d < users.csv

# Redact credit-card-shaped numbers, everything else untouched
$ teip -og '\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b' -- \
       sed 's/./*/g' < support-tickets.txt

# Parse only the timestamp column with dateutils
$ teip -D '\t' -f 2 -- dateutils.dconv -f '%s' < events.tsv

The flag zoo is small and orthogonal:

The safety property is what makes teip trustworthy in production: unless you pass -s, teip refuses to splice back a subcommand output whose line count differs from what it sent. If your transform silently ate a line you get an error, not garbled output — the exact failure mode that eventually bites every hand-rolled awk-plus-system() pipeline.

Performance-wise, the subcommand runs once as a coprocess and streams. On a million-line log, replacing awk '{ "cmd " $3 | getline x; ... }' with teip commonly moves you from minutes to a couple of seconds because you stopped forking a million times.

Fun corner: teip -s -f 1- is a legitimate way to slurp all fields into a single subprocess call, which turns teip into a general "wrap this command around the whole stream, but I still want its output on the same lines" utility.

Key Takeaway: teip fills the exact gap between sed's DSL limits and the horror of pipeline scaffolding — apply any command to any substring, keep everything else byte-for-byte, and get a hard error instead of silent corruption if the transform changes the line count.

All newsletters