Совместные Процессы Bash

Одной из новых функций Bash 4.0 является coproc. Оператор coproc позволяет создать сопроцесс, который взаимодействует с оболочкой по двум каналам: один для отправки данных в сопроцесс и один для получения данных от сопроцесса.

Впервые я нашел этому применение при попытке записать журнал с использованием перенаправления.

руководитель .

Цель заключалась в том, чтобы при необходимости разрешить запись вывода сценария в файл журнала после запуска сценария (например, из-за опции --бревно командная строка).

Основная проблема с протоколированием вывода после запуска сценария заключается в том, что его вывод уже мог быть перенаправлен (в файл или канал).

Если мы перенаправим уже перенаправленный вывод, мы не сможем выполнить команду так, как задумал пользователь.

Предыдущая реализация была выполнена с использованием именованных каналов:

  
  
  
  
  
  
  
  
   

#!/bin/bash echo hello if test -t 1; then # Stdout is a terminal. exec >log else # Stdout is not a terminal. npipe=/tmp/$$.

tmp trap "rm -f $npipe" EXIT mknod $npipe p tee <$npipe log & exec 1>&- exec 1>$npipe fi echo goodbye

Из прошлого статьи :
Здесь, если стандартный поток вывода скрипта не подключен к терминалу, мы создаем трубка (именованный канал, расположенный в файловой системе), используя мкнод , и с помощью ловушка мы удаляем его, когда скрипт завершает работу.

Затем мы бежим тройник , который в фоновом режиме связывает входной поток с созданным каналом.

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

Также помните, что выходной поток тройник направляется в то же место, что и весь вывод скрипта (вызывающий скрипт тройник ).

Таким образом, вывод тройник в конечном итоге окажется там, где в данный момент направлен выходной поток сценария (то есть в перенаправленный пользователем поток вывода или конвейер, указанный при вызове сценария в командной строке).

Таким образом, мы получаем стандартный вывод тройник куда нам это нужно: в определяемый пользователем канал перенаправления или конвейера.

Мы можем сделать то же самое с совместными процессами:

echo hello if test -t 1; then # Stdout is a terminal. exec >log else # Stdout is not a terminal. exec 7>&1 coproc tee log 1>&7 #echo Stdout of coproc: ${COPROC[0]} >&2 #echo Stdin of coproc: ${COPROC[1]} >&2 #ls -la /proc/$$/fd exec 7>&- exec 7>&${COPROC[1]}- exec 1>&7- eval "exec ${COPROC[0]}>&-" #ls -la /proc/$$/fd fi echo goodbye echo error >&2

Если наш стандартный вывод поступает на терминал, мы просто используем руководитель чтобы перенаправить наш вывод в нужный файл журнала.

Если вывод не связан с терминальным устройством, то для запуска используем coproc. тройник как совместный процесс и перенаправить наш вывод на вход тройник и выйти тройник перенаправляем туда, где изначально планировалось.

Запуск тройник использование coproc по сути работает так же, как tee в фоновом режиме (например, тройник и ), главное отличие в том, что к нему подключены оба канала (входной и выходной).

По умолчанию, Баш помещает файловые дескрипторы этих каналов в массив КОПРОК .

  • КОПРОК[0] это файловый дескриптор канала, подключенного к стандартному выводу сопроцесса;
  • КОПРОК[1] подключен к стандартному входу совместного процесса.

Обратите внимание, что эти каналы необходимо создать до использования перенаправлений в команде.

Обратите внимание на часть сценария, где вывод сценария не подключен к терминалу.

Следующая строка дублирует наш стандартный вывод в файловый дескриптор 7.

exec 7>&1

Затем мы начинаем тройник его вывод перенаправляется в файловый дескриптор 7.

coproc tee log 1>&7

Сейчас тройник запишет все, что прочитает из стандартного ввода, в файл с именем бревно и файловый дескриптор 7, который является нашим текущим стандартным выводом.

Теперь мы закроем файловый дескриптор 7 (помните, что тройник также «файл», который открывается в 7 как стандартный вывод):

exec 7>&-

Поскольку мы закрыли 7, мы можем использовать его снова, поэтому мы перемещаем канал, подключенный к входу 7. тройник :

exec 7>&${COPROC[1]}-

Затем мы перемещаем наш стандартный вывод в канал, подключенный к стандартному входу.

тройник (наш файловый дескриптор равен 7) через:

exec 1>&7-

И, наконец, закрываем канал, подключенный к выходу тройник , так как он нам больше не нужен:

eval "exec ${COPROC[0]}>&-"

В этом случае оценивать здесь необходимо, потому что в противном случае Баш считает, что ценность ${КОПРОК[0]} это команда.

С другой стороны, это и не требуется выше ( exec 7> &${COPROC[1]}- ), потому что Баш знает, что «7» инициирует операцию с файловым дескриптором и не считается командой.

Также обратите внимание на закомментированную строку:

#ls -la /proc/$$/fd

Это полезно для просмотра файлов, открытых текущим процессом.

Теперь мы достигли желаемого эффекта: наш стандартный вывод будет направлен на тройник .

ты тройник есть «вход» в наш лог-файл и запись идет как в тот канал, так и в тот файл, который планировался изначально.

Никаких других задач для сопроцессов, по крайней мере не надуманных, я пока придумать не могу.

См.

страницу мужик ругается для получения дополнительной информации о совместных процессах.

Теги: #*nix #Системное администрирование #bash #coproc

Вместе с данным постом часто просматривают: