Leia o comando, pule as instruções subsequentes no HEREDOC - Bash + Docker

Leia o comando, pule as instruções subsequentes no HEREDOC - Bash + Docker

Estou tendo problemas com um caso que considero um bug no funcionamento do shell ou bash, no qual a execução de um comando não interativo fornecido por um heredoc (talvez de um arquivo também, não testei) e um read(ou semelhante) no heredoc, faz com que o código após um readcomando sejaignorado, e a execução terminasem erros, executando os comandosdepoiso comando que executa o heredoc.

Mais especificamente, estou executando o código em um contêiner docker que atua como uma caixa de ferramentas para vários utilitários do Linux, e esse problema faz com que o código não seja realmente seguro, no sentido de que não posso confiar que isso acontecerá como espero.

Uma amostra do problema pode ser vista abaixo:

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    read 'var'
    echo "after inside" >&2
SHELL

echo "after outside" >&2

Eu esperava que o código acima executasse todos os ecos e terminasse com sucesso ou gerasse um erro no readcomando e terminasse com um erro.

Infelizmente, a saída do código acima é:

before outside
before inside
after outside

Basicamente ignorou o que estava depois do readcomando, talvez porque tenha uma readinstrução em um comando que não aloca um pseudo-tty ( docker run -italoca um pseudo-tty, mas não pode executar o código acima, por causa do heredoc que é canalizado para o comando, em vez disso ele fornece o erro the input device is not a TTY:).

Se eu remover o 2 set -eou pipefailtenho o mesmo problema, mesmo usando read 'var' ||:, então não acho que tenha relação com (um dosPegadinhasde) set -e.

Um exemplo de resultado esperado é o seguinte:

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    unknow_command error ||:
    echo "after inside" >&2
SHELL

echo "after outside" >&2

Que termina com sucesso e imprime:

before outside
before inside
/bin/bash: line 3: unknow_command: command not found
after inside
after outside

Ou:

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    unknow_command error
    echo "after inside" >&2
SHELL

echo "after outside" >&2

Que termina com um erro e imprime:

before outside
before inside
/bin/bash: line 3: unknow_command: command not found

Para mim estaria tudo bem se o readcomando fosse simplesmente ignorado (com um valor vazio como entrada, por exemplo) e todos os comandos posteriores fossem executados, mesmo os do heredoc, ou que desse um erro e parasse a execução imediatamente (se Não ignoro o erro no comando docker).

O acima foi apenas um exemplo, em um caso real pode ser muito pior porque o readcomando (ou similar) pode não ser chamado diretamente, mas dentro de um comando, e apenas sob algumas condições. Por exemplo:

#!/bin/bash
set -eou pipefail

docker run --rm -i my_mysql /bin/bash <<-SHELL
    set -eou pipefail
    some_important_command_1
    mysql -u "$user" -p "$pass" -e "some sql command"
    some_important_command_2
SHELL

some_important_command_after_2

O código acima pode parecer bom, mas se a senha estiver vazia, ele tentará ler do stdin, causando o problema no primeiro exemplo, pulando some_important_command_2, mas executando some_important_command_after_2isso deve ser executado somente depois some_important_command_2.

O exemplo do mysql acima também foi apenas um exemplo, posso verificar neste caso se a senha está vazia e tratar dela.O verdadeiro problema é que não consigo determinar se esse problema pode acontecer dentro de um código e não vejo nenhuma maneira segura de evitá-lo, além de interromper o uso do contêiner docker toolbox e instalar todos os utilitários e outras coisas dentro de todos os hosts e mantê-los atualizados (em vez de apenas manter a imagem do contêiner atualizada). Também não funcionará para comandos executados especificamente em serviços dentro de contêineres (como o exemplo do mysql acima).

Alguém tem uma solução para o problema acima?Uma solução quenão é específicoaos exemplos que dei, mas uma abordagem geral que pode resolveresse tipo de bug(seja concluindo com sucesso, executando todos os comandos ou dando um erro e interrompendo todos os comandos subsequentes).

Atualizar:

Adicionando saídas declare -p varposteriores echo "after inside":

before outside
before inside
declare -- var="echo \"after inside\" >&2"
after outside

Acho que o comando read acaba lendo o heredoc como @muru apontou nos comentários. Também posso ver se adicionar echo "var=\$var"after echo "after inside", que imprime: var=echo "after inside" >&2. Então agora preciso encontrar uma maneira de pular essas leituras do próprio heredoc.

informação relacionada