Как Вы используете команду coproc в различных оболочках?

Я не уверен, что можно сделать это сразу, вот обходное решение:

screen -t 'fubar' cmd & sleep .01; screen -X other
81
10.07.2018, 10:32
4 ответа

совместно обрабатывает a ksh функция (уже в ksh88). zsh имел функцию от запуска (в начале 90-х), в то время как это было просто только добавлено к bash в 4.0 (2009).

Однако поведение и интерфейс существенно отличаются между 3 оболочками.

Идея является тем же, хотя: это позволяет запускать задание в фоне и способности отправить ему вход и считать его вывод, не имея необходимость обращаться к именованным каналам.

Это сделано с каналами без имени с большинством оболочек и socketpairs с последними версиями ksh93 в некоторых системах.

В a | cmd | b, a данные подачи к cmd и b читает его вывод. Выполнение cmd поскольку совместно обрабатывание позволяет оболочке быть обоими a и b.

ksh совместно обрабатывает

В ksh, Вы запускаете совместно обрабатывание как:

cmd |&

Вы подаете данные к cmd путем выполнения вещей как:

echo test >&p

или

print -p test

И читайте cmdвывод с вещами как:

read var <&p

или

read -p var

cmd запускается как любое фоновое задание, можно использовать fg, bg, kill на нем и отсылают его %job-number или через $!.

Закрыть конец записи канала cmd читает из, можно сделать:

exec 3>&p 3>&-

И закрыть конец чтения другого канала (тот cmd пишет в):

exec 3<&p 3<&-

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

tr a b |&
exec 3>&p 4<&p
tr b c |&
echo aaa >&3
echo bbb >&p

zsh совместно обрабатывает

В zsh, совместно обрабатывает почти идентичны тем, которые в ksh. Единственная реальная разница - это zsh совместно обрабатывает запускаются с coproc ключевое слово.

coproc cmd
echo test >&p
read var <&p
print -p test
read -p var

Выполнение:

exec 3>&p

Примечание: Это не перемещается coproc дескриптор файла к fd 3 (как в ksh), но дубликаты это. Так, нет никакого явного способа закрыть питание или чтение канала, другой запуск другого coproc.

Например, для закрытия питающегося конца:

coproc tr a b
echo aaaa >&p # send some data

exec 4<&p     # preserve the reading end on fd 4
coproc :      # start a new short-lived coproc (runs the null command)

cat <&4       # read the output of the first coproc

Кроме того, для передачи по каналу базирующийся совместно обрабатывает, zsh (так как 3.1.6-dev19, выпущенный в 2000), имеет базирующиеся конструкции pseudo-tty как expect. Для взаимодействия с большинством программ ksh-стиль совместно обрабатывает, не будет работать, так как программы начинают буферизовать, когда их вывод является каналом.

Вот некоторые примеры.

Запустите совместно обрабатывание x:

zmodload zsh/zpty
zpty x cmd

(Здесь, cmd простая команда. Но можно сделать более необычные вещи с eval или функции.)

Подайте совместно обрабатывать данные:

zpty -w x some data

Читайте совместно обрабатывают данные (в самом простом случае):

zpty -r x var

Как expect, это может ожидать некоторого вывода от совместно обрабатывать соответствия данному шаблону.

удар совместно обрабатывает

Синтаксис удара является намного более новым, и создает сверх новой опции, недавно добавленной к ksh93, удару и zsh. Это обеспечивает синтаксис, чтобы позволить обрабатывать динамично выделенных дескрипторов файлов выше 10.

bash предлагает основное coproc синтаксис и расширенный.

Базовый синтаксис

Базовый синтаксис для запуска совместно обрабатывания похож zsh:

coproc cmd

В ksh или zsh, с каналами к и от совместно обрабатывания получают доступ >&p и <&p.

Но в bash, дескрипторы файлов канала от совместно обрабатывания и другого канала к co-proccess возвращаются в $COPROC массив (соответственно ${COPROC[0]} и ${COPROC[1]}. Так …

Данные канала к совместно обрабатыванию:

echo xxx >&"${COPROC[1]}"

Считайте данные с совместно обрабатывания:

read var <&"${COPROC[0]}"

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

Расширенный синтаксис

В расширенном синтаксисе можно назвать Ваш, совместно обрабатывает (как в zsh zpty co-proccesses):

coproc mycoproc { cmd; }

Команда должна быть составной командой. (Заметьте, как пример выше напоминает о function f { ...; }.)

На этот раз дескрипторы файлов находятся в ${mycoproc[0]} и ${mycoproc[1]}.

Можно запустить, больше чем один совместно обрабатывает за один раз — но Вы действительно получаете предупреждение при запуске совместно обрабатывания, в то время как каждый все еще работает (даже в неинтерактивном режиме).

Можно закрыть дескрипторы файлов при использовании расширенного синтаксиса.

coproc tr { tr a b; }
echo aaa >&"${tr[1]}"

exec {tr[1]}>&-

cat <&"${tr[0]}"

Обратите внимание, что закрытие того пути не работает в версиях удара до 4,3, где необходимо записать это вместо этого:

fd=${tr[1]}
exec {fd}>&-

Как в ksh и zsh, те дескрипторы файлов канала отмечены как замыкаться-должностное-лицо.

Но в bash, единственный способ передать тех, которые к выполняемым командам, состоит в том, чтобы копировать их к fds 0, 1, или 2. Это ограничивает количество, совместно обрабатывает Вас, может взаимодействовать с для единственной команды. (См. ниже для примера.)

процесс yash и конвейерное перенаправление

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

Вы запустили бы совместно обрабатывание с:

exec 5>>|4 3>(cmd >&5 4<&- 5>&-) 5>&-

Который сначала создает a pipe(4,5) (5 конец записи, 4 конец чтения), затем перенаправляет fd 3 к каналу к процессу, который работает с его stdin и stdout, идущим в канал, созданный ранее. Затем мы закрываем конец записи того канала в родителе, в котором мы не будем нуждаться. Таким образом, теперь в оболочке нам подключили fd 3 к stdin cmd и fd 4, подключенному к stdout cmd с каналами.

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

Подавать данные:

echo data >&3 4<&-

Считывать данные:

read var <&4 3>&-

И можно закрыть fds, как обычно:

exec 3>&- 4<&-

Теперь, почему они не так популярны

едва любое преимущество по использованию именованных каналов

Совместно обрабатывает может легко быть реализован со стандартными именованными каналами. Я не знаю, когда точно именованные каналы были представлены, но возможно, что это было после ksh придумал совместно обрабатывает (вероятно, в середине 80-х, ksh88 был "выпущен" в 88, но я верю ksh использовался внутренне в AT&T за несколько лет до того), который объяснит почему.

cmd |&
echo data >&p
read var <&p

Может быть записан с:

mkfifo in out

cmd <in >out &
exec 3> in 4< out
echo data >&3
read var <&4

Взаимодействие с теми более просто — особенно, если необходимо работать, больше чем один совместно обрабатывает. (См. примеры ниже.)

Единственное преимущество использования coproc это, Вы не должны мыться тех именованных каналов после использования.

склонный к мертвой блокировке

Оболочки используют каналы в нескольких конструкциях:

  • каналы оболочки: cmd1 | cmd2,
  • замена команды: $(cmd),
  • и замена процесса: <(cmd), >(cmd).

В тех, потоках данных только в одном направлении между различными процессами.

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

работы, хуже, чем expect поскольку, для чего это было разработано

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

Самая простая форма упомянутой выше мертвой блокировки:

tr a b |&
echo a >&p
read var<&p

Поскольку его вывод не переходит к терминалу, tr буферизует его вывод. Таким образом, это ничего не произведет ни до одного, который это видит конец файла на stdin, или это накопило буферно-полные из данных для вывода. Таким образом выше, после того, как оболочка произвела a\n (только 2 байта), read заблокируется неограниченно долго потому что tr ожидает оболочки, чтобы отправить ему больше данных.

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

Вот почему expect или zpty используйте псевдотерминалы вместо этого. expect инструмент, разработанный для взаимодействия с командами, и оно делает это хорошо.

Обработка дескриптора файла трудна, и трудно разобраться

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

то, что другой Unix. Ответ SE имеет пример coproc использования.

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

Все каналы использования.

Например: подайте вывод printf '%s\n' foo bar кому: tr a b, sed 's/./&&/g', и cut -b2- получить что-то как:

foo
bbr
ffoooo
bbaarr
oo
ar

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

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

Например, с zsh, Вы сделали бы это с:

f() (
  coproc tr a b
  exec {o1}<&p {i1}>&p
  coproc sed 's/./&&/g' {i1}>&- {o1}<&-
  exec {o2}<&p {i2}>&p
  coproc cut -c2- {i1}>&- {o1}<&- {i2}>&- {o2}<&-
  tee /dev/fd/$i1 /dev/fd/$i2 >&p {o1}<&- {o2}<&- &
  exec cat /dev/fd/$o1 /dev/fd/$o2 - <&p {i1}>&- {i2}>&-
)
printf '%s\n' foo bar | f

Выше, совместно обрабатывание fds сделало, чтобы замыкаться-должностное-лицо отметило набор, но не тех, которые дублированы от них (как в {o1}<&p). Так, для предотвращения мертвых блокировок необходимо будет удостовериться, что они закрываются в любых процессах, для которых не нужны они.

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

С ksh (здесь ksh93), это должно было бы быть:

f() (
  tr a b |&
  exec {o1}<&p {i1}>&p
  sed 's/./&&/g' |&
  exec {o2}<&p {i2}>&p
  cut -c2- |&
  exec {o3}<&p {i3}>&p
  eval 'tee "/dev/fd/$i1" "/dev/fd/$i2"' >&"$i3" {i1}>&"$i1" {i2}>&"$i2" &
  eval 'exec cat "/dev/fd/$o1" "/dev/fd/$o2" -' <&"$o3" {o1}<&"$o1" {o2}<&"$o2"
)
printf '%s\n' foo bar | f

(Примечание: Это не будет работать над системами где ksh использование socketpairs вместо pipes, и где /dev/fd/n работы как на Linux.)

В ksh, fds выше 2 отмечены с флагом замыкаться-должностного-лица, если они не передаются явно на командной строке. Вот почему мы не должны закрывать неиспользованные дескрипторы файлов как с zsh— но это также, почему мы должны сделать {i1}>&$i1 и используйте eval для того нового значения $i1, быть переданным tee и cat

В bash это не может быть сделано, потому что Вы не можете избежать флага замыкаться-должностного-лица.

Выше, это относительно просто, потому что мы используем только простые внешние команды. Это становится более сложным, когда Вы хотите использовать конструкции оболочки там вместо этого, и Вы начинаете сталкиваться с ошибками оболочки.

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

f() {
  mkfifo p{i,o}{1,2,3}
  tr a b < pi1 > po1 &
  sed 's/./&&/g' < pi2 > po2 &
  cut -c2- < pi3 > po3 &

  tee pi{1,2} > pi3 &
  cat po{1,2,3}
  rm -f p{i,o}{1,2,3}
}
printf '%s\n' foo bar | f

Заключение

Если Вы хотите взаимодействовать с командой, использовать expect, или zsh zpty, или именованные каналы.

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

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

121
27.01.2020, 19:30
  • 1
    Большой ответ действительно. Я не знаю, когда конкретно это было зафиксировано, но с, по крайней мере, bash 4.3.11, можно теперь закрыть coproc дескрипторы файлов непосредственно без потребности в aux. переменной; с точки зрения примера в Вашем ответе exec {tr[1]}<&- теперь работал бы (для закрытия stdin coproc; обратите внимание, что Ваш код (косвенно) пытается закрыться {tr[1]} использование >&-, но {tr[1]} stdin coproc и должен согласиться <&-). Фиксация, должно быть, прибыла куда-нибудь между 4.2.25, который все еще показывает проблему, и 4.3.11, который не делает. –  mklement0 15.04.2015, 00:03
  • 2
    @mklement0, спасибо. exec {tr[1]}>&- действительно кажется, работает с более новыми версиями и ссылается в записи CWRU/changelog (позвольте словам как {массив [ind]} быть допустимым перенаправлением... 01.09.2012). exec {tr[1]}<&- (или более корректное >&- эквивалентный, хотя это не имеет никакого значения как тот просто вызовы close() для обоих), не закрывает stdin coproc, но конец записи канала к этому coproc. –  Stéphane Chazelas 07.06.2015, 23:26
  • 3
    @mklement0, положительная сторона, я обновил его и добавил yash. –  Stéphane Chazelas 08.06.2015, 11:44
  • 4
    Одно преимущество mkfifo это, Вы не должны волноваться об условиях состязания и безопасности для доступа канала. Все еще необходимо волноваться о мертвой блокировке с FIFO. –  Otheus 19.11.2016, 14:55
  • 5
    О мертвых блокировках: stdbuf команда может помочь предотвратить по крайней мере некоторых из них. Я использовал его в соответствии с Linux и ударом. Так или иначе я полагаю, что @StéphaneChazelas является правильным в Заключении: "голова, царапающая" фазу, законченную для меня только, когда я переключился назад на именованные каналы. –  shub 24.05.2017, 04:33

Совместно обрабатывает были сначала представлены на языке сценариев оболочки с ksh88 оболочка (1988), и позже в zsh в какой-то момент до 1993.

Синтаксис для запуска совместно обрабатывания под ksh command |&. Начиная оттуда, можно записать в command стандартный вход с print -p и считайте его стандартный вывод с read -p.

Больше чем несколько десятилетий спустя удар, который испытывал недостаток в этой функции наконец, представил ее в своих 4,0 выпусках. К сожалению, несовместимый и более сложный синтаксис был выбран.

Под ударом 4.0 и более новый, можно запустить совместно обрабатывание с coproc команда, например:

$ coproc awk '{print $2;fflush();}'

Можно затем передать что-то команде stdin тот путь:

$ echo one two three >&${COPROC[1]}

и считайте вывод awk с:

$ read -ru ${COPROC[0]} foo
$ echo $foo
two

Под ksh, который был бы:

$ awk '{print $2;fflush();}' |&
$ print -p "one two three"
$ read -p foo
$ echo $foo
two
7
27.01.2020, 19:30

Что такое "coproc"?

Это коротко для, "совместно обрабатывают", что означает второй процесс, сотрудничающий с оболочкой. Это очень похоже на фоновое задание, запущенное с "и" в конце команды, за исключением того, что вместо того, чтобы совместно использовать тот же стандартный ввод и вывод как его родительская оболочка, его стандартный ввод-вывод подключен к родительской оболочке специальным видом канала, названного ссылкой FIFO.For, щелкают здесь

Каждый запускает coproc в zsh с

coproc command

Команда должна быть готова читать из stdin и/или записать в stdout, или это не имеет большого применения как coproc.

Прочитайте эту статью здесь, она обеспечивает тематическое исследование между должностным лицом и coproc

-1
27.01.2020, 19:30
  • 1
    Можно ли добавить часть статьи к ответу? Я пытался покрыть эту тему в U&L, так как это казалось под представленным. Спасибо за Ваш ответ! Также заметьте, что я установил тег как Bash, не zsh. –  slm♦ 10.08.2013, 21:23
  • 2
    @slm Вы уже указали на хакеров Bash. Я видел там достаточные примеры. Если Ваше содержание должно было принести этот вопрос под вниманием затем да, Вы успешно выполнились:> –  Valentin Bajrami 10.08.2013, 21:42
  • 3
    , Они не специальные виды каналов, они - те же каналы, как используется с |. (который является каналами использования в большинстве оболочек и socketpairs в ksh93). каналы и socketpairs являются методом "первым пришел - первым вышел", они - весь FIFO. mkfifo делает именованные каналы, совместно обрабатывает, не используют именованные каналы. –  Stéphane Chazelas 10.08.2013, 23:35
  • 4
    @slm, жаль о zsh... на самом деле, я работаю над zsh. Я склонен делать это иногда с потоком. Это хорошо работает в Bash также... –  Munai Das Udasin 11.08.2013, 00:27
  • 5
    Stephane Chazelas, я вполне уверен, что я считал его где-нибудь, что это - ввод-вывод, соединен со специальными видами каналов, названных FIFO... –  Munai Das Udasin 11.08.2013, 00:33

Вот еще один хороший (и рабочий) пример - простой сервер, написанный на BASH. Обратите внимание, что вам понадобится OpenBSD netcat , классический не работает. Конечно, вы можете использовать сокет inet вместо unix.

server.sh :

#!/usr/bin/env bash

SOCKET=server.sock
PIDFILE=server.pid

(
    exec </dev/null
    exec >/dev/null
    exec 2>/dev/null
    coproc SERVER {
        exec nc -l -k -U $SOCKET
    }
    echo $SERVER_PID > $PIDFILE
    {
        while read ; do
            echo "pong $REPLY"
        done
    } <&${SERVER[0]} >&${SERVER[1]}
    rm -f $PIDFILE
    rm -f $SOCKET
) &
disown $!

client.sh :

#!/usr/bin/env bash

SOCKET=server.sock

coproc CLIENT {
    exec nc -U $SOCKET
}

{
    echo "$@"
    read
} <&${CLIENT[0]} >&${CLIENT[1]}

echo $REPLY

Использование:

$ ./server.sh
$ ./client.sh ping
pong ping
$ ./client.sh 12345
pong 12345
$ kill $(cat server.pid)
$
-1
27.01.2020, 19:30

Теги

Похожие вопросы