2026-04-24
You're piping 80 GB of database dump through gzip into mysql and your terminal just... sits there. No output. No progress. Is it 10% done? 95%? Dead? You open htop in another terminal and squint at I/O numbers like a diviner reading tea leaves.
pv (pipe viewer) is a 20-year-old utility that splices into any pipeline and gives you a real-time progress bar, ETA, throughput rate, and total bytes transferred. It's the single most useful tool nobody installs by default.
Install it everywhere:
apt install pv # Debian/Ubuntu
brew install pv # macOS
dnf install pv # Fedora/RHEL
The simplest use — monitor a file copy through a pipe:
pv bigfile.sql.gz | gunzip | mysql mydb
# 3.12GiB 0:02:41 [19.8MiB/s] [============> ] 62% ETA 0:01:37
That's it. Stick pv in the pipe and suddenly you're not flying blind. But the real power is in the flags most people never discover.
Rate limiting. Need to throttle a restore so your production database doesn't melt?
pv -L 10m backup.sql | mysql prod_db
That's a hard cap at 10 MB/s. No ionice gymnastics, no cgroups. Just -L.
Multiple pv stages. You can insert pv at several points to see where your bottleneck lives:
pv -cN raw dump.sql.gz | gunzip | pv -cN decomp | mysql mydb
# raw: 1.2GiB 0:01:02 [19.5MiB/s]
# decomp: 4.8GiB 0:01:02 [78.1MiB/s]
The -c flag enables cursor positioning so multiple bars don't clobber each other, and -N gives each a label. Now you can see the compression ratio in real time and know instantly whether you're I/O bound or CPU bound.
Monitoring data you don't have a file size for. When piping from a stream (no known size), you can supply an estimate:
ssh remote "pg_dump bigdb" | pv -s 50g | gzip > bigdb.sql.gz
The percentage and ETA will be approximate, but approximate beats nothing.
The dd replacement nobody talks about. Writing disk images? Stop using dd with no feedback:
# Instead of: dd if=image.iso of=/dev/sdb bs=4M
pv image.iso | dd of=/dev/sdb bs=4M
Full progress bar. No sending kill -USR1 to a dd process like a caveman.
Generating test data at controlled rates. Need to simulate a log stream at exactly 1000 lines per second?
pv -qL 50k /dev/urandom | base64 | head -c 1G > testdata.bin
The timer trick. Just want elapsed time and average throughput on any pipeline, no progress bar?
some_process | pv -t -b > /dev/null
# 0:00:47 2.31GiB
Flags: -t for timer, -b for total byte count. Clean, scriptable output.
Combining with tar for directory transfers:
tar cf - /data/warehouse | pv -s $(du -sb /data/warehouse | awk '{print $1}') | \
ssh remote "tar xf - -C /backup"
Accurate progress bar on a remote directory copy, no rsync needed.
The beauty of pv is that it embodies the Unix philosophy perfectly — it does exactly one thing (show you what's moving through a pipe) and composes with everything. Any place you have a |, you can insert pv.
pv — it gives you progress bars, throughput, ETAs, and rate limiting with zero changes to the rest of your pipeline.
