Знаете, я не уверен, что вам обязательно нужен повторяющийся цикл обратной связи, как изображают ваши диаграммы, настолько, насколько возможно вы могли бы использовать постоянный конвейер между сопроцессами . С другой стороны, это может быть не так уж много различий - когда вы открываете строку в сопроцессе, вы можете реализовать типичные циклы стилей, просто записывая информацию и читая информацию из нее, не делая ничего необычного.
Во-первых, может показаться, что bcдля вас это главный кандидат на сопроцесс. В bcвы можете defineфункции , которые могут сделать очень многое , что вы просите в вашем псевдокод. Например, некоторые очень простые функции для этого могут выглядеть так:
printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN
... который будет печатать ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
Но, конечно, это не последний . Как только подоболочка, отвечающая за printfканал, завершает работу (сразу после printfзаписи a()\nв канал), канал разрушается, и bcввод закрывается, и он также завершает работу. Это не так полезно, как могло бы быть.
@derobert уже упомянул FIFO, что можно сделать, создав файл именованного канала с помощью mkfifoутилиты. По сути, это также просто каналы, за исключением того, что ядро системы связывает запись файловой системы с обоих концов. Они очень полезны, но было бы лучше, если бы вы могли просто иметь канал, не рискуя получить его в файловой системе.
Как это бывает, ваша оболочка делает это много. Если вы используете оболочку, которая реализует подстановку процессов, то у вас есть очень простые способы получения прочного канала - такого типа, который вы можете назначить фоновому процессу, с которым вы можете общаться.
В bash, например, вы можете увидеть , как заместительная процесс работы:
bash -cx ': <(:)'
+ : /dev/fd/63
Вы видите, что это действительно замена . Оболочка заменяет значение во время расширения, которое соответствует пути к ссылке на канал . Вы можете воспользоваться этим - вам не нужно ограничивать использование этого канала только для связи с любым процессом, выполняемым внутри самой ()замены ...
bash -c '
eval "exec 3<>"<(:) "4<>"<(:)
cat <&4 >&3 &
echo hey cat >&4
read hiback <&3
echo "$hiback" here'
... который печатает ...
hey cat here
Теперь я знаю, что разные оболочки выполняют процесс сопроцессора по-разному, и что существует специальный синтаксис bashдля его настройки (и, вероятно, zshтакже для), но я не знаю, как эти вещи работают. Я просто знаю , что вы можете использовать приведенные выше синтаксис делать практически то же самое , не все канитель в обоих bashи zsh- и вы можете сделать очень похожую вещь в dashи busybox ashдля достижения той же цели с здесь-документов (потому что dashи busyboxделать здесь- документы с конвейерами, а не временные файлы, как у двух других) .
Итак, применительно к bc...
eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"
... это сложная часть. И это самое интересное ...
set --
until [ "$#" -eq 10 ]
do printf '%s()\n' b c a >&"$BCIN"
set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"
... который печатает ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965
... и он все еще работает ...
echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"
... который просто возвращает мне последнее значение для bcs aвместо вызова a()функции для его увеличения и печатает ...
.29566669586771958965
Фактически, он будет продолжать работать, пока я не убью его и не разорву его каналы IPC ...
kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT