Использование UNIX: Что внутри конвейера?

Отслеживаем прогресс выполнения длительных операций с помощью Pipe Viewer

Оператор конвейера позволяет соединить две UNIX®-команды для выполнения нужных программ непосредственно в командной строке. Однако конвейер похож на черный ящик, скрывающий процесс передачи данных от одной утилиты к другой. Программа Pipe Viewer позволяет взглянуть на поток данных, проходящих через конвейер. В даннной статье вы узнаете, как использовать его в повседневных задачах.

Мартин Стрейчер (Martin Streicher), независимый web-разработчик, IBM

Мартин Стрейчер (Martin Streicher) (Jeff J. Li) - фотографияМартин Стрейчер (Martin Streicher) - независимый web-разработчик и бывший главный редактор Linux Magazine. Он имеет степень магистра компьютерных наук Университета Пардью (Purdue University) и занимается программированием в UNIX-подобных операционных системах с 1986 года. Он коллекционирует предметы искусства и игрушки.


developerWorks Contributing author
        level

10.11.2010

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

Часто используемые сокращения

  • GUI: Графический интерфейс пользователя (Graphical user interface)

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

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

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

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

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

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

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

Рисунок 1. Создание конвейера, соединяющего два процесса
Steps used to create a pipe

В начале, на фазе 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. Соединяем команды с помощью конвейеров
Connecting and counting files with names that begin with x

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

Рисунок 3. Исследуем два UNIX-процесса
an interprocess exchange that Looks into two UNIX processes

Мы сделали краткий обзор конвейеров, теперь давайте познакомимся поближе с утилитой 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.


Маленькая драгоценность

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

Ресурсы

Научиться

  • Speaking UNIX: Peering into pipes - оригинал статьи (EN).
  • Использование UNIX: ознакомьтесь с другими статьями серии.(EN)
  • Узнайте больше об оболочках UNIX.(EN)
  • На сайте developerWorks в разделе AIX и UNIX вы всегда сможете найти огромное количество справочных материалов, касающихся всех аспектов администрирования систем AIX.(EN)
  • Посетите электронный магазин технической литературы Safari, чтобы найти интересующую вас информацию.(EN)

Получить продукты и технологии

  • Узнайте больше информации о Pipe Viewer и загрузите его.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=578308
ArticleTitle=Использование UNIX: Что внутри конвейера?
publish-date=11102010