Como implementar stdout deferido no processo filho sem usar arquivos temporários?

4

Eu tenho um programa (nomeie-o middle ) que não posso modificar.
Este programa executa a seguinte sequência de etapas:

  • middle envia algum texto para stdout ( echo Text1 )
  • middle chama o script de shell inner.sh passando uma string de texto (4 KB ou menos) como argumento ( inner.sh "Deferred Message" )
  • middle envia algum texto para stdout ( echo Text2 )

Minha tarefa é criar dois scripts bash outer.sh e inner.sh para organizar mensagens adiadas após todas as outras mensagens geradas por middle process.
O stdout resultante deve ser o seguinte:

Text1
Text2
Deferred Message

Os requisitos:

  • outer.sh deve invocar middle (e middle invocará inner.sh ).
  • inner.sh deve lembrar seu argumento (mensagem adiada) em algum lugar
  • Depois que middle for finalizado, outer.sh deverá recuperar a mensagem adiada e imprimi-la na stdout
  • Haverá muitos processos outer.sh em execução simultaneamente. A mensagem adiada deve ser armazenada em um local que seja local para a instância atual de outer.sh process
  • A criação de objetos temporários no sistema de arquivos é proibida. (É possível armazenar a mensagem adiada em algum lugar na memória?)

inner.sh

# Where should I save message "$1"?

outer.sh

middle "$@"
# How should I recall and print the deferred message?

Onde devo salvar a mensagem adiada no processo filho e como lê-la de volta no processo pai?

    
por Egor Skriptunoff 23.07.2017 / 10:17

1 resposta

7

inner.sh poderia ser:

printf '%s\n' "$1" >&3

e em outer.sh , você poderia fazer:

{ inner=$(middle "$@" 3>&1 >&4 4>&-); } 4>&1
printf '%s\n' "$inner"

O texto interno é passado por meio de um pipe (na substituição do comando) e armazenado em uma variável do shell. Isso pressupõe que middle não feche o fd 3 antes de invocar inner.sh (não há razão para isso).

Explicação:

  • %código%. Nesse grupo de comandos, inicialmente, tanto fd 1 como 4 apontam para o stdout original. IOW, fizemos uma cópia do stdout do outer.sh para o fd 4 para poder recuperá-lo dentro da substituição do comando
  • %código%. Dentro dessa substituição de comando, stdout (fd 1) é um pipe. Esse é o ponto de substituição de comando. Quer pegar a saída do comando. Mas aqui, nós não queremos o stdout de { ... } 4>&1 , queremos o que ele (ou mais exatamente o seu filho $(...) ) escreve no fd 3, então:
  • middle : para inner.sh , tornamos fd 3 o pipe cmdsubst, de forma que o que middle 3>&1 >&4 4>&- escreve vai para middle e restauramos o stdout de inner.sh para o salvo stdout original em fd 4. Fechamos fd 4 depois de ter servido o seu propósito, pois $inner não precisa fazer nada com ele.
por 23.07.2017 / 10:45