Conheço dois tipos de como os comandos podem ser conectados:
- usando um Pipe (colocando std-output na std-input do próximo comando).
- usando um Tee (divida a saída em várias saídas).
Eu não sei se isso é tudo o que é possível, então eu desenho um tipo de conexão hipotética:
Como seria possível implementar um fluxo circular de dados entre comandos como, por exemplo, neste pseudo-código, onde eu uso variáveis em vez de comandos .:
pseudo-code:
a = 1 # start condition
repeat
{
b = tripple(a)
c = sin(b)
a = c + 1
}
fonte
Em geral, eu usaria um Makefile (comando make) e tentaria mapear seu diagrama para regras de makefile.
Para ter comandos repetitivos / cíclicos, precisamos definir uma política de iteração. Com:
cada
make
um produzirá uma iteração por vez.fonte
make
, mas desnecessário: se você usa um arquivo intermediário, por que não usar apenas um loop para gerenciá-lo?make
trata-se de macros, que é uma aplicação perfeita aqui.Você sabe, não estou convencido de que você precise necessariamente de um ciclo de feedback repetitivo, como retratam seus diagramas, tanto quanto talvez você possa usar um pipeline persistente entre os coprocessos . Por outro lado, pode ser que não exista muita diferença - uma vez que você abre uma linha em um coprocessador, pode implementar loops típicos de estilo, escrevendo e lendo informações e lendo informações sem fazer nada fora do comum.
Em primeiro lugar, parece que você
bc
é o principal candidato a um co-processo. Embc
você podedefine
funções que podem fazer praticamente o que você pede em seu pseudocódigo. Por exemplo, algumas funções muito simples para fazer isso podem parecer:... o que imprimiria ...
Mas é claro que não dura . Assim que o subconjunto responsável
printf
pelo tubo do encerra (logo após aprintf
gravaçãoa()\n
no tubo), o tubo é desmontado ebc
a entrada é fechada e também é encerrada. Isso não é tão útil quanto poderia ser.O @derobert já mencionou FIFO s, como pode ser obtido criando um arquivo de pipe nomeado com o
mkfifo
utilitário. Também são essencialmente apenas canais, exceto que o kernel do sistema vincula uma entrada do sistema de arquivos às duas extremidades. Isso é muito útil, mas seria melhor se você pudesse ter um canal sem correr o risco de ser espionado no sistema de arquivos.Por acaso, seu shell faz muito isso. Se você usa um shell que implementa a substituição do processo , você tem um meio muito simples de obter um canal duradouro - do tipo que você pode atribuir a um processo em segundo plano com o qual você pode se comunicar.
Em
bash
, por exemplo, você pode ver como a substituição do processo funciona:Você vê que é realmente uma substituição . O shell substitui um valor durante a expansão que corresponde ao caminho para um link para um pipe . Você pode tirar proveito disso - você não precisa ser obrigado a usar esse canal apenas para se comunicar com qualquer processo executado dentro da
()
própria substituição ...... que imprime ...
Agora eu sei que diferentes shells executam o processo de coprocessamento de maneiras diferentes - e que existe uma sintaxe específica
bash
para configurar uma (e provavelmente umazsh
também) - mas não sei como essas coisas funcionam. Eu apenas sei que você pode usar a sintaxe acima para fazer praticamente a mesma coisa sem todo o rigmarole em ambosbash
ezsh
- e você pode fazer uma coisa muito semelhantedash
ebusybox ash
alcançar o mesmo objetivo com os documentos aqui (porquedash
ebusybox
faça aqui- documentos com tubos em vez de arquivos temporários, como os outros dois) .Então, quando aplicado a
bc
...... essa é a parte mais difícil. E esta é a parte divertida ...
... que imprime ...
... e ainda está em execução ...
... o que me dá o último valor de
bc
, ema
vez de chamar aa()
função para incrementá-lo e imprimi-lo ...De fato, ele continuará funcionando até que eu o mate e destrua os canos do IPC ...
fonte
eval "exec {BCOUT}<>"<(:) "{BCIN}<>"<(:)
funciona também