MyTetra Share
Делитесь знаниями!
Время создания: 19.11.2010 16:49
Текстовые метки: pv, pipe, viewer
Раздел: Шпаргалки - Команды
Запись: balas1/mytetra/master/base/0000003246/text.html на raw.github.com

Одной из самых умных и мощных инноваций в UNIX является оболочка. Она эффективнее, чем графический интерфейс и позволяет создавать сценарии для автоматизации многих задач. Более того, с помощью конвейера команд можно конструировать импровизированные программы непосредственно в командной строке. Конвейер собирает команды в цепочки, в которых стандартный вывод одной команды становится стандартным вводом для следующей команды.

Но у конвейера есть один серьезный недостаток: он похож на черный ящик. Когда вы соединяете две команды, единственным признаком хода выполнения процесса является вывод, генерируемый последней в последовательности командой. Можно вставить в последовательность команду tee, а также наблюдать за ростом выходного файла с помощью tail, но эти решения отлично работают только при однократном применении в команде, в противном случае стандартные потоки вывода (stdout) и стандартные потоки ошибок (stderr) различных фаз перемешиваются. К тому же оба эти решения являются грубыми индикаторами, которые, вероятно, не покажут, сколько в действительности вычислений требуется на каждом шаге.

Конечно, можно разбить сложную последовательность команд на множество отдельных шагов, каждый из которых будет генерировать свой собственный выходной файл. В самом деле, если вы хотите проверять результат работы на каждом интервале, декомпозиция является идеальным решением. Создайте сценарий, в котором на каждом шаге генерируйте отдельный файл с данными и используйте его в качестве входных данных для следующего шага и т.д. В результате вы получите файл с итоговыми результатами. Однако такая практика плохо подходит к импровизационной природе командной строки.

То, что нам нужно – это индикатор прогресса выполнения задачи, который можно встраивать в командную строку для измерения скорости передачи данных. В идеале хорошо было бы использовать этот индикатор повторно, чтобы сравнивать производительность на каждом шаге. Ну и, поскольку нет предела совершенству, хорошо бы, чтобы это был инструмент с открытым кодом, который бы работал с различными вариантами UNIX, такими как Linux® и Mac OS X.

Всем нашим пожеланиям удовлетворяет программа Pipe Viewer (pv), написанная системным администратором Эндрю Вудом (Andrew Wood) и улучшаемая на протяжении последних четырех лет многими другими разработчиками. Она позволяет заглянуть внутрь "трубопровода" командной строки. Как говорится на домашней странице проекта, pv "можно вставлять в конвейер между двумя процессами для получения визуальной индикации того, как быстро передаются между ними данные, как много времени прошло и насколько близко завершение работы". Заметим, что для измерения относительной производительности можно использовать pv несколько раз в одной последовательности команд.

В этой статье рассказывается о том, как собрать pv для своей UNIX-системы и применять ее для простых и сложных комбинаций инструментов командной строки. Давайте начнем с обзора того, как процессы обмениваются друг с другом данными с помощью конвейеров.

Конвейеры UNIX: трубопровод для процессов

На рисунке 1 показаны этапы создания конвейера, соединяющего два независимых процесса.
Рисунок 1. Создание конвейера, соединяющего два процесса

В начале, на фазе 1, процесс-инициатор читает данные из stdin, выводит результат в stdout, а ошибки в stderr. stdin, stdout и stderr являются файловыми дескрипторами. Каждая операция, выполняемая с файловым дескриптором, например open, read, write, rewind, truncate или close, изменяет состояние файла.

Затем в фазе 2 процесс-инициатор создает конвейер. Конвейер состоит из очереди и двух файловых дескрипторов. Один нужен, чтобы помещать данные в очередь, другой - чтобы извлекать их из очереди. Конвейер представляет собой структуру данных типа FIFO (первым пришел - первым вышел).

Сам по себе конвейер мало полезен; он предназначен для того, чтобы соединять процесс-поставщик и процесс-потребитель (данных). Поэтому процесс-инициатор в фазе 3 ответвляет или создает себе процесс, с которым будет работать в паре.

В фазе 4 (предполагая, что новый процесс является потребителем данных), исходный процесс заменят свой stdout дескриптором, помещающим данные в конвейер, а stdin только что созданного процесса - дескриптором, считывающим данные из конвейера. После этих манипуляций каждая операция write исходного процесса (поставщика) будет помещена в очередь и впоследствии прочитана новым процессом (потребителем).

Фазы 1-4 иллюстрируют то, как оболочка соединяет с помощью конвейера (|) две утилиты одну с другой в командной строке. Заметим только, что оболочка создает для каждой утилиты новый процесс, а сама занимается управлением ходом работы.

Например, на рисунке 2 показано, как можно с помощью конвейеров соединить команды find, grep и wc, чтобы найти и подсчитать количество файлов, имена которых начинаются с буквы a в нижнем регистре. Оболочка остается независимой; вывод find служит входным потоком для grep, результат работы которого в свою очередь направляется команде wc. wc обрабатывает полученные от grep данные и выводит результат своей работы в stdout. Обычно оболочка выводит stdout на терминал, но его также можно перенаправить в файл.
Рисунок 2. Соединяем команды с помощью конвейеров

Если вы хотите изучить работу двух UNIX-процессов, создайте два конвейера и переопределите файловые дескрипторы процессов так, чтобы они являлись друг для друга и поставщиком и потребителем данных. На рисунке 3 показан обмен данными между процессами, в котором для обоих процессов переопределяются потоки stdin и stdout.
Рисунок 3. Исследуем два UNIX-процесса

Мы сделали краткий обзор конвейеров, теперь давайте познакомимся поближе с утилитой Pipe Viewer.


В начало

Pipe Viewer: примечательный конвейер

Pipe Viewer - это приложение с открытым исходным кодом. Можно загрузить его код и собрать приложение с нуля или загрузить исполняемый файл программы из репозитория вашего дистрибутива UNIX, если он там имеется.

Для самостоятельной сборки загрузите архив с последней версией исходного кода с домашней страницы проекта Pipe Viewer (см. Ресурсы). В сентябре 2009 года последней версией являлась 1.1.4. Распакуйте архив, перейдите в созданную директорию и выполните ./configure, затем make и sudo make install. По умолчанию исполняемый файл программы называется pv и помещается в /usr/local/bin. (Чтобы просмотреть имеющиеся параметры конфигурации, выполните ./configure --help.) В листинге 1 показан код установки pv.
Листинг 1. Код установки Pipe Viewer

$ wget http://pipeviewer.googlecode.com/files/pv-1.1.4.tar.bz2

$ tar xjf pv-1.1.4.tar.bz2

$ cd pv-1.1.4

$ ./configure

$ make

$ sudo make install

$ which pv

/usr/local/bin/pv


Чтобы скачать исполняемый файл программы pv из репозитория, найдите с помощью менеджера пакетов своего дистрибутива имеющиеся пакеты по словам pv или pipe viewer. Например в Ubuntu 9 поиск с помощью менеджера пакетов APT дает следующий результат:

$ apt-cache search part viewer

pv - Shell pipeline element to meter data passing through


Загрузите и установите пакет с помощью своего менеджера пакетов. В Ubuntu это делается командой apt-get install:

$ sudo apt-get install pv


Теперь давайте опробуем pv в действии. В простейшем варианте использования pv может заменять традиционную утилиту cat для передачи байтов другой программе и измерения общей производительности. Например, можно использовать pv для отслеживания длительной операции сжатия:

$ ls -lh listings.txt

-r--r--r-- 1 supergiantrobot staff 109M Sep 1 20:47 listings.txt

$ pv listings.txt | gzip > listings.gz

96.1MB 0:00:09 [11.3MB/s] [=====================> ] 87% ETA 0:00:01


При запуске pv отображает индикатор прогресса, который показывает и непрерывно обновляет различные показатели хода выполнения работы. Обычно pv слева направо отображает количество обработанных данных, прошедшее время, производительность в мегабайтах в секунду, а также визуальное и численное представление количества проделанной работы и оценки оставшегося времени. В приведенном выше примере обработано 96.1МБ из 109МБ, и на оставшиеся 13% файла потребуется примерно 9 секунд

По умолчанию pv отображает все индикаторы состояния, значения которых он может вычислить. Например, если входные данные pv не являются файлом, и не указано вручную точного размера, индикатор прогресса перемещается слева направо, чтобы отображать активность программы, но pv не сможет определить процент выполненной работы. Например:

$ ssh faraway tar cf - projectx | pv --wait > projectx.tar

Password:

4.34MB 0:00:07 [ 611kB/s] [ <=> ]


В этом примере на удаленной машине выполняется команда tar, результат работы которой отправляется на локальную систему в файл projectx.tar. Поскольку pv не может вычислить общее количество байтов, которые будут переданы, он показывает производительность, истекшее время и специальный индикатор, отображающий активность программы. Он представляет собой маленький индикатор (<=>), который перемещается слева направо по мере передачи данных.

Параметр --wait откладывает отображение индикатора прогресса до момента фактического получения первого байта. Здесь --wait полезен, так как команда ssh может предложить ввести пароль.

Можно включать индикаторы по своему усмотрению, указывая флаги с говорящими именами:

$ ssh faraway tar cf - projectx | \

pv --wait --bytes > projectx.tar

Password:

268kB


В этой команде с помощью флага --bytes включается отображение количества переданных байтов. Также есть параметры --progress, --timer, --eta, --rate и --numeric. Если вы указываете один или более из этих параметров, все оставшиеся (неуказанные) индикаторы автоматически выключаются.

Есть еще одно простое применение pv. Параметр --rate-limit может ограничивать пропускную способность. Этот параметр принимает в качестве аргументов число и суффикс, обозначающий единицу измерения. Например, m обозначает число мегабайтов в секунду:

$ ssh faraway tar cf - projectx | \

pv --wait --quiet --rate-limit 1m > projectx.tar


Предыдущая команда выключает все индикаторы (--quiet) и ограничивает пропускную способность скоростью 1МБ/с.


В начало

Более сложное использование Pipe Viewer

До сих пор в наших примерах использовался только один экземпляр Pipe Viewer, который выступал в роли поставщика или потребителя данных в паре команд. Однако возможны и более сложные комбинации. Соблюдая некоторые условия, можно использовать несколько экземпляров pv в одной командной строке. А именно: необходимо с помощью параметра --name указать имя каждому экземпляру pv и включить многострочный режим с помощью параметра --cursor. Вместе эти два параметра создают серию именованных индикаторов, по одному индикатору на экземпляр (программы).

Например, мы хотим отслеживать одновременно и по отдельности процессы передачи данных и их сжатия. Мы назначаем один экземпляр pv первой операции, и еще один - второй:

$ ssh faraway tar cf - projectx | pv --wait --name ssh | \

gzip | pv --wait --name gzip > projectx.tgz


После ввода пароля мы увидим,что Pipe Viewer показывает двухстрочный индикатор активности:

ssh: 4.17MB 0:00:07 [ 648kB/s] [ <=> ]

gzip: 592kB 0:00:06 [62.1kB/s] [ <=> ]


Первая строка с надписью ssh показывает прогресс передачи данных. Вторая строка с надписью gzip показывает прогресс сжатия данных. Поскольку ни одна из команд не может определить объем данных в своей операции, на каждой строке показан объем переданных данных и индикатор активности.

Если вы знаете, или можете оценить или вычислить объем данных, обрабатываемых операцией, то можно использовать параметр --size. Добавив этот параметр, вы получите более подробную информацию в индикаторах прогресса.

Например, если мы хотим отслеживать прогресс большой задачи архивирования, то можно использовать другие утилиты UNIX, чтобы оценить общий размер исходных файлов. Утилита df может показывать статистику для целой файловой системы, а du может вычислить размер иерархии файлов произвольной глубины:

$ tar cf - work | pv --size `du -sh work | cut -f1` > work.tar


Здесь последовательность команд du -sh work | cut -f1 выдает общий размер рабочей директории в формате, совместимом с pv. Команда du -h генерирует данные в удобочитаемом формате, например 17M для 17 мегабайт, который подходит для использования с pv. (Команды ls и df также поддерживают параметр -h для вывода данных в удобочитаемом формате). Так как теперь pv ожидает, что через конвейер будет передано определенное количество байтов, он отображает полноценный индикатор прогресса:

700kB 0:00:07 [ 100kB/s] [> ] 4% ETA 0:02:47


И наконец, есть еще один прием, который наверняка будет вам полезен. Помимо подсчета байтов, Pipe Viewer может визуализировать прогресс операции, подсчитывая строки данных. Если указать модификатор --line-mode, то pv обновляет индикатор прогресса каждый раз при встрече новой строки. Также можно указать параметр --size, тогда число будет интерпретировано как ожидаемое количество строк.

Рассмотрим пример. Команда find часто бывает полезной, когда нужно найти иголку в стоге сена, например, чтобы отыскать все места, где в большом количестве кода используется определенный системный вызов. В таких случаях можно воспользоваться подобной командой:

$ find . -type f -name '*.c' -exec grep --files-with-match fopen \{\} \; > results


Этот код находит все файлы исходного кода на C и возвращает имена файлов, в которых встречается строка fopen. Результат работы направляется в файл с именем results. Для отражения активности добавим команду pv:

$ find . -type f -name '*.c' -exec grep --files-with-match fopen \{\} \; | \

pv --line-mode > results


Строковый режим феноменален, потому что многие команды UNIX, например find, оперируют метаданными файлов, а не их содержимым. Строковый режим идеально подходит для сценариев системного администрирования, которые копируют или сжимают большое количество файлов.

В общем, Pipe Viewer можно вставлять в командной строке и сценариях везде, где можно измерить скорость передачи данных. . Иногда требуется быть изобретательным – например, чтобы измерить скорость копирования директории, можно перейти от cp -pr к tar:

$ # an equivalent of cp -pr old/somedir new

$ (cd old; tar cf - somedir) | pv | (cd new; tar xf - )


Также строковый режим можно использовать при работе с сетевыми утилитами, такими как wget, curl и scp. Например, можно использовать pv для отображения выполнения процесса передачи известного объема данных на удаленную машину. И, поскольку многие сетевые утилиты могут считывать входные данные из файла, можно использовать размер такого файла в качестве аргумента для параметра --size.

 
MyTetra Share v.0.59
Яндекс индекс цитирования