Я не уверен, что можно сделать это сразу, вот обходное решение:
screen -t 'fubar' cmd & sleep .01; screen -X other
совместно обрабатывает a ksh
функция (уже в ksh88
). zsh
имел функцию от запуска (в начале 90-х), в то время как это было просто только добавлено к bash
в 4.0
(2009).
Однако поведение и интерфейс существенно отличаются между 3 оболочками.
Идея является тем же, хотя: это позволяет запускать задание в фоне и способности отправить ему вход и считать его вывод, не имея необходимость обращаться к именованным каналам.
Это сделано с каналами без имени с большинством оболочек и socketpairs с последними версиями ksh93 в некоторых системах.
В a | cmd | b
, a
данные подачи к cmd
и b
читает его вывод. Выполнение cmd
поскольку совместно обрабатывание позволяет оболочке быть обоими a
и b
.
В 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
, совместно обрабатывает почти идентичны тем, которые в 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
имеет интерфейс к 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
, или именованные каналы.
Если Вы хотите сделать некоторую необычную инфраструктуру с каналами, используйте именованные каналы.
Совместно обрабатывает может сделать часть вышеупомянутого, но готов сделать некоторую серьезную голову, царапающую для чего-либо нетривиального.
Совместно обрабатывает были сначала представлены на языке сценариев оболочки с 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
Что такое "coproc"?
Это коротко для, "совместно обрабатывают", что означает второй процесс, сотрудничающий с оболочкой. Это очень похоже на фоновое задание, запущенное с "и" в конце команды, за исключением того, что вместо того, чтобы совместно использовать тот же стандартный ввод и вывод как его родительская оболочка, его стандартный ввод-вывод подключен к родительской оболочке специальным видом канала, названного ссылкой FIFO.For, щелкают здесь
Каждый запускает coproc в zsh с
coproc command
Команда должна быть готова читать из stdin и/или записать в stdout, или это не имеет большого применения как coproc.
Прочитайте эту статью здесь, она обеспечивает тематическое исследование между должностным лицом и coproc
|
. (который является каналами использования в большинстве оболочек и socketpairs в ksh93). каналы и socketpairs являются методом "первым пришел - первым вышел", они - весь FIFO. mkfifo
делает именованные каналы, совместно обрабатывает, не используют именованные каналы.
– Stéphane Chazelas
10.08.2013, 23:35
Вот еще один хороший (и рабочий) пример - простой сервер, написанный на 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)
$
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:03exec {tr[1]}>&-
действительно кажется, работает с более новыми версиями и ссылается в записи CWRU/changelog (позвольте словам как {массив [ind]} быть допустимым перенаправлением... 01.09.2012).exec {tr[1]}<&-
(или более корректное>&-
эквивалентный, хотя это не имеет никакого значения как тот просто вызовыclose()
для обоих), не закрывает stdin coproc, но конец записи канала к этому coproc. – Stéphane Chazelas 07.06.2015, 23:26yash
. – Stéphane Chazelas 08.06.2015, 11:44mkfifo
это, Вы не должны волноваться об условиях состязания и безопасности для доступа канала. Все еще необходимо волноваться о мертвой блокировке с FIFO. – Otheus 19.11.2016, 14:55stdbuf
команда может помочь предотвратить по крайней мере некоторых из них. Я использовал его в соответствии с Linux и ударом. Так или иначе я полагаю, что @StéphaneChazelas является правильным в Заключении: "голова, царапающая" фазу, законченную для меня только, когда я переключился назад на именованные каналы. – shub 24.05.2017, 04:33