Долгая операция в терминале без индикации прогресса вызывает закономерное беспокойство: зависла она или работает, закончится через минуту или к утру. Классический случай - dd на десятки гигабайт, который по замыслу UNIX молчит до конца, и единственный индикатор - время. Утилита pv (pipe viewer) решает проблему с минимумом суеты: она вставляется в любой пайп и рисует счётчик переданных байт, скорость, ETA и полоску прогресса. В статье разбираем повседневные сценарии: dd с прогрессом, архивация с индикацией, копирование через ssh, ограничение скорости и ncruses-подобные финты, которые делают работу заметно приятнее.

Установка и базовое использование

pv почти наверняка есть в репозитории вашего дистрибутива: apt install pv или dnf install pv, и весит утилита ничего. Базовый паттерн: pv источник > приёмник, и в терминале появляется знакомая всем строка вида 1,5GiB 0:00:10 [ 150MiB/s] [=======> ] 45% ETA 0:00:12. Слева направо: сколько передано, сколько прошло времени, текущая скорость, визуальный прогресс и оценка оставшегося времени.

Ключевая деталь: ETA и полоска появляются только если pv знает полный объём. Читаем из файла - размер известен по stat. Читаем из потока (например, tar cf - каталог, размер заранее неизвестен) - pv покажет только счётчик и скорость. Для потоков есть выход: параметр -s задаёт ожидаемый размер вручную. Оценить объём через du -sb каталог и подставить в pv -s это стандартный приём, после которого даже tar-поток обрастает красивым индикатором.

dd с нормальным прогрессом, главный повседневный кейс

Запись образа на USB-флешку это идеальный пример: без прогресса dd if=image.iso of=/dev/sdX bs=4M молчит десять минут, и единственное спасение это присылаемый из второго терминала kill -USR1, заставляющий dd напечатать счётчик. С pv всё проще: pv image.iso | dd of=/dev/sdX bs=4M oflag=direct conv=fsync, и весь вечерный ритуал с мигающим курсором остаётся в прошлом - скорость, объём и ETA на экране с первой секунды.

Полезные модификации: pv -n выводит голую строку с числами для встраивания в скрипты, pv -e рисует только ETA, а pv -t - только таймер. Для автоматизации удобен -q (quiet) когда индикатор не нужен, но нужны побочные эффекты вроде ограничения скорости, о которых речь ниже. И да, dd сам умеет status=progress, доступный в GNU coreutils уже много лет, и на pgrep к нему можно не ходить; pv выигрывает универсальностью: он работает с любыми программами, а не только с dd.

Архивация и бэкапы, индикация длительных операций

Вторая естественная вотчина pv это архивация. Классический сценарий бэкапа через tar: tar cf - /var/lib/myapp | pv -s $(du -sb /var/lib/myapp | cut -f1) | zstd -3 -T0 > backup.tar.zst - и вот уже архивация смотрится как полоса прогресса, а не молчащий чёрный экран. Здесь -s держит оценку общего объёма, и процент будет корректным настолько, насколько честным был du.

Третий сценарий - дампы баз данных: pg_dump mydb | pv | gzip > mydb.sql.gz показывает реальный темп выгрузки и снимает главный вопрос 'оно живо?'. Четвёртый сценарий - сетевое копирование: tar cf - /data | pv | ssh backup@host 'cat > /srv/incoming/data.tar' передаёт данные и показывает текущую скорость канала, что заодно служит экспресс-тестом сети между ЦОДами: увидеть цифру в 900+ МБ/с в момент пересылки это заметно информативнее, чем предположения про гигабит.

Для синхронизации каталогов существует pv в паре с rsync --progress, но rsync уже всё показывает сам; pv пригождается там, где rsync избыточен: прямое копирование блочных устройств, cat данных в fifo, перенос виртуальных дисков. Общий принцип: любой поток данных через пайп может быть снабжён приборной панелью за ноль копеек и без вмешательства в сами команды.

Ограничение скорости, pv как шейпер для файловых операций

Неочевидное, но чрезвычайно практичное свойство pv это параметр -L, ограничивающий скорость потока. Смысл: на продовом сервере в рабочий день копирование гигантского файла способно уронить производительность дисковой подсистемы, которую делят приложения. Ставим затвор: pv -L 50m bigfile.img > /mnt/slow/bigfile.img, и копия идёт 50 МБ/с, не мешая никому.

Аналогично ограничивается сетевой трафик: tar cf - /data | pv -L 30m | ssh remote 'cat > /backup/data.tar' аккуратно пролезает на 30 МБ/с и не вызывает гнева сетевиков в бизнес-часы. Искусство тут в калибровке: -L задаётся в байтах в секунду с суффиксами k, m, g, и практическая метка это где-то треть-половина реальной пропускной способности канала или диска, чтобы остальные процессы не чувствовали голода.

Используют -L и в противоположную сторону - для имитации медленного канала при тестировании: на localhost приложение проверяется против штатных таймаутов с ограничением в 100 КБ/с, и всплывают баги обработки медленных ответов, которые на гигабите просто не случаются.

Скриптинг и тонкости встраивания

В скриптах pv требует аккуратности с окружением. Первое: индикатор пишется в stderr, поэтому в логах cron-задач выгодно добавить -q или перенаправить 2>/dev/null, иначе лог зарастёт тысячами строк обновления счётчика. Второе: pv нетерминальна обнаруживает отсутствие TTY автоматически и молчит сама, но принудительный -f включает вывод даже в файл, что бывает нужно в отладке.

Третье: возврат ошибок. pv честно возвращает код неудачи, если источник не читается, но в пайпе по умолчанию exit code определяется последней командой; включайте pipefail в shell, чтобы сбой pv не утопал в успехе последнего звена. Четвёртое: в старых shell-сценариях двойной pv подряд - pv file | pv > dest - даёт редкую нужную картину скорости с обеих сторон, но обычно это уже декорация.

Когда pv не нужна и другие флаги на каждый день

Противопоказаний у pv немного, но они есть. На крошечных операциях секундного масштаба индикатор просто не нужен. Внутри длинных производственных цепочек, уже идущих под стражей наблюдателя вроде резервного решения с собственным прогрессом, добавление pv - шум. На системах, где её нельзя поставить политиками, приходится жить с dd status=progress и прочими местными вариантами, но административный шум там обычно выше пользы индикатора.

Из флагов, которые стоит знать наизусть: -s размер для потоков, -L лимит скорости, -q тишина, -n цифры для скриптов, -c многострочный индикатор при нескольких pv в одном пайпе (у каждого своя строка, идеально для метрик длинных цепочек), -a средняя скорость, -e ETA, -r текущая скорость (показывается по умолчанию). Этих букв хватает, чтобы описать любой нужный формат вывода.

Если свести практику применения к паре слов: pv это приборная панель и регулятор громкости для потоков данных, который ставится за минуту, ничего не ломает, и превращает тягостное ожидание долгих файловых операций в нормальный рабочий процесс, где видно, что происходит и когда закончится. Администратор, однажды привыкнув к прогресс-бару на dd, вряд ли уже согласится жить без него.
## Комбинации, которые выручают в реальной работе

Трюк из практики с несколькими индикаторами: в длинной цепочке tar | zstd | ssh хочется видеть обе стороны процесса. Используем -c: tar cf - /data | pv -cN source | zstd -3 -T0 | pv -cN compressed | ssh backup@host 'cat > /srv/data.tar.zst' - и две строки прогресса покажут скорость чтения с диска и итоговую скорость записи в сеть. Разница между ними наглядно показывает, где реальное узкое место: если source 400 МБ/с, а compressed 90 МБ/с, вы считаете CPU; если обе упёрлись в десяток мегабайт, тормозит WAN-канал.

Второй рабочий приём это pv вокруг медленного источника: при чтении с ленты, старого USB-диска или сетевой шары на CIFS индикатор показывает не просто прогресс, а сам факт жизни процесса. Местный вариант: время от времени глазами сверяется скорость с ожиданиями; резкое падение тока - сигнал заглянуть в dmesg на предмет битых секторов или сетевого затыка. Без pv такая деградация осталась бы незамеченной до окончания операции в воскресенье вечером.

Третий приём - checkpoint-логгирование: pv -n 2>progress.log позволяет CI-системе наблюдать за ходом длительной выгрузки и принимать решения по реальному числу байт, а не по догадке. Четвёртый, самый будничный: pv просто ставится между любыми двумя командами, когда новую цепочку гоняете в первый раз, чтобы понимать порядок величин; потом из финального скрипта она убирается, оставив -q или не оставив вовсе.

Запись образов блочных устройств целиком

Отдельного разговора заслуживает копирование целых дисков. Переезд системы на новый SSD это десятки-сотни гигабайт блочных данных, и связка pv /dev/sdX | dd of=/dev/sdY bs=4M conv=sparse превращает непрозрачное копание в предсказуемый процесс с ETA. Важные дополнения: conv=sparse экономит время на пустых участках, oflag=direct обходит страничный кэш и улучшает честность измерения конечной скорости, а status=none у dd убирает его собственную статистику, чтобы не путалась с выводом pv.

При клонировании между серверами тот же принцип переносится на ssh: pv /dev/sdX | ssh host 'dd of=/dev/sdY bs=4M conv=sparse' - переезд виртуального диска на другой гипервизор без промежуточных файлов, c полной видимостью темпа. А если цель это образ-файл, дополнительное сжатие по ходу не даст в два раза меньший файл, но наполовину: pv /dev/sdX | zstd -6 -T0 > disk.img.zst.

Наблюдения о привычке, которая остаётся навсегда

Все администраторы, однажды взявшие pv в инструментарий, отмечают у него одно и то же качество: он становится невидимой частью рук. Команды чуть длиннее, зато появляется уверенность в протекании каждого движения данных. Постепенно приходит и калибровка: вы знаете, сколько мегабайт в секунду отдаёт ваш диск, ваш usb-канал, ваш бэкапный сервер, просто потому что pv стоял в пайпе и показывал правду. Это редкий инструмент, который честно учит инженера собственной инфраструктуре, не требуя для этого ни дня специального изучения.

Альтернативы и дальние родственники pv

Существуют соседние инструменты, о которых полезно знать, чтобы выбирать осознанно. mbuffer делает акцент на буферизации потока - его ставят между источником и приёмником, чтобы сгладить неравномерность, например между быстрым диском и медленной лентой, и прогресс у него тоже есть. ddrescue это спасательный инструмент для битых дисков: он копирует блоки с пропуском повреждённых областей и ведением карты, и вот там pv применять мимо кассы - у ddrescue собственный отличный индикатор. progress (бывший cv) умеет подсматривать прогресс уже запущенных процессов coreutils - копий cp, mv, dd, что удобно, когда забыли вставить индикатор на старте и процесс уже работает час.

Итог сравнения простой: pv это прибор к пайпам, ddrescue - к больным дискам, progress - к уже бегущим командам, mbuffer - к асимметричным паркам потребления и производства. У каждого своя территория, и pv по-прежнему остаётся самой универсальной кнопкой под названием 'покажи, что происходит'.

Памятка запуска на каждый день

Запоминать флаги не обязательно, достаточно завести пару алиасов в ~/.bashrc: alias dd-progress='pv | dd oflag=direct conv=fsync bs=4M' это черновик, а на постоянное место в .bashrc лучше записать короткую памятку с примерами на свой профиль задач. Со временем вырабатывается стабильный набор из трёх-четырёх команд с pv под ваши ежедневные задачи, и дальше весь этот раздел превращается просто в мышечную память: вставил pv, увидел цифры, пошёл пить чай в спокойствии.
На этом и закончим: инструмент крошечный, а количество спасённых нервных клеток, которые раньше убывали на гипотезу "неужели зависло", не поддаётся исчислению - и это лучшая известная мера пользы терминальной программы.
Если же вы читаете эту статью без pv под рукой, проверьте менеджер пакетов прямо сейчас: утилита ставится за секунду и занимает меньше места, чем эта страница в памяти браузера.
Точка.