A intenção do script de teste 1 abaixo é iniciar um coprocesso "externo" (executando seq 3
), ler desse coprocesso em um while
-loop e, para cada linha lida, imprimir uma linha identificando a iteração atual do loop externo, iniciar um " internal" (também executando seq
, com novos argumentos), leia esse coprocesso interno em um loop while aninhado e, em seguida, limpe esse coprocesso interno. O laço while aninhado imprime alguma saída para cada linha que lê do coprocesso interno.
#!/bin/bash
# filename: coproctest.sh
PATH=/bin:/usr/bin
coproc OUTER { seq 3; }
SAVED_OUTER_PID="${OUTER_PID}"
exec {OUTER_READER}<&"${OUTER[0]}"
while IFS= read -r -u "${OUTER_READER}" OUTER_INDEX; do
printf -- '%d\n' "${OUTER_INDEX}"
START=$(( OUTER_INDEX * 1000000 ))
FINISH=$(( START + OUTER_INDEX ))
# (
coproc INNER { seq "${START}" "${FINISH}"; }
SAVED_INNER_PID="${INNER_PID}"
exec {INNER_READER}<&"{INNER[0]}"
while IFS= read -r -u "${INNER_READER}" INNER_INDEX; do
printf -- ' %d\n' "${INNER_INDEX}"
done
exec {INNER_READER}<&-
wait "${SAVED_INNER_PID}"
# )
done
exec {OUTER_READER}<&-
wait "${SAVED_OUTER_PID}"
Quando executo este script, esta é a saída que recebo:
% ./coproctest.sh
1
./coproctest.sh: line 30: warning: execute_coproc: coproc [12523:OUTER] still exists
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
2
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
3
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
Eu recebo praticamente a mesma saída se eu descomentar as duas linhas comentadas.
Q1: É possível ter vários coprocessos em execução ao mesmo tempo?
Q2: Em caso afirmativo, como o script acima deve ser modificado para obter a saída desejada?
1 Só recentemente comecei a trabalhar com coprocessos, e ainda tem muita coisa que não entendo. Como resultado, esse script quase certamente contém código incorreto, estranho ou desnecessário. Sinta-se à vontade para comentar e/ou corrigir esses pontos fracos em suas respostas.
Da seção "BUGS" no final do
bash
manual:No Bash v4 e superior (incluindo a v5 atual), oficialmente não, conforme observado por @Kusalananda.
No entanto, posso dizer-lhe que pode funcionar apesar do aviso, mas é claro que não há garantia e YMMV. Veja aqui um pouco mais de visão.
Pode ( conforme acima) funcionar bem quando você corrigir o:
que provoca:
mensagem e, consequentemente, também:
mensagem.
Funciona para mim, uma vez corrigido isso e aviso à parte.
Quanto a outras notas:
coproc
os descritores de arquivo de um , a menos que você queira passá-los para um processo filho (um sub-shell ou um comando ou script)seq
comando naturalmente terminou rapidamente e, portanto, as variáveis automáticas desapareceram antes que você pudesse usá-las. Fazendo o que você fez, esses descritores de arquivo duplicados serão herdados por todos os comandos subsequentes e processos em segundo plano, o que pode ser indesejável se seu co-processo realmente usar seu pipe de entrada e esperar que ele seja fechado para sair. Então, outra abordagem para resolver isso é por um mecanismo de sincronização, como, por exemplo, fazer seuOUTER
co-processo ser{ seq 3; exec >&-; read; }
, e então quando você consumir sua entrada do script principal, por exemploecho >&${OUTER[1]}; wait "${OUTER_PID}"
, deixar o co-processoread
prosseguirwait
para ele. Observe que não é garantido que owait
será executado antes do$OUTER_PID
variável desaparece: nesse caso, você pode apenas silenciar a mensagem de aviso (ou ignorá-la completamente) e talvez forçar um status de sucesso com um|| true
coproc
do uso da sintaxe Bash v3 sobre processos em segundo plano maismkfifo
FIFOs nomeados, e no Linux também com um truque com substituições de processo em vez demkfifo
s. Com a sintaxe Bash v4, pode ser menos complicado, mas ainda é um exercício desafiador.