Leer comando omitir instrucciones posteriores en HEREDOC - Bash + Docker

Leer comando omitir instrucciones posteriores en HEREDOC - Bash + Docker

Tengo problemas con un caso que veo como un error en el funcionamiento del shell o bash, en el que se ejecuta un comando no interactivo proporcionado desde un heredoc (tal vez también desde un archivo, no lo he probado) y un read(o similar) comando en el heredoc, hace que el código después de un readcomando seaignorado, y la ejecución hasta el finalsin errores, ejecutando los comandosdespuésel comando que ejecuta el heredoc.

Más específicamente, estoy ejecutando código en un contenedor acoplable que actúa como una caja de herramientas para varias utilidades de Linux, y este problema hace que el código no sea realmente seguro en el sentido de que no puedo confiar en que suceda como espero.

A continuación se puede ver una muestra del problema:

#!/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

Esperaba que el código anterior ejecutara todos los ecos y finalizara correctamente, o diera un error en el readcomando y finalizara con un error.

Desafortunadamente, el resultado del código anterior es:

before outside
before inside
after outside

Básicamente ignoró lo que había después del readcomando., tal vez porque tiene una readinstrucción en un comando que no asigna un pseudo-tty ( docker run -itasigna un pseudo-tty, pero no puede ejecutar el código anterior, debido al documento heredoc que está canalizado al comando, en lugar de eso, proporciona el error: the input device is not a TTY).

Si elimino el 2 set -eou pipefailtengo el mismo problema, incluso usando read 'var' ||:, así que no creo que esté relacionado con (uno de lostrampasde) set -e.

Un ejemplo de un resultado esperado es el siguiente:

#!/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

Lo cual finaliza con éxito e imprime:

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

O:

#!/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

Lo cual termina con un error e imprime:

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

Para mí, estaría bien si el readcomando simplemente se omitiera (con un valor vacío como entrada, por ejemplo) y se ejecutaran todos los comandos posteriores, incluso los del heredoc, o que diera un error y detuviera la ejecución inmediatamente (si No ignoro el error en el comando de la ventana acoplable).

Lo anterior fue solo un ejemplo, en un caso real puede ser mucho peor porque el readcomando (o similar) no puede llamarse directamente, sino dentro de un comando, y solo bajo algunas condiciones. Por ejemplo:

#!/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

El código anterior puede parecer correcto, pero si la contraseña está vacía, intentará leer desde la entrada estándar, causando el problema en el primer ejemplo, omitiendo some_important_command_2, pero ejecutándose some_important_command_after_2solo debería ejecutarse después de some_important_command_2.

El ejemplo anterior de MySQL también fue solo un ejemplo. En este caso puedo verificar si la contraseña está vacía y manejarla.El verdadero problema es que no puedo determinar si este problema puede ocurrir dentro de un código y no veo una forma segura de evitarlo., además de detener el uso del contenedor de la caja de herramientas de Docker e instalar todas las utilidades y otras cosas dentro de todos los hosts, y mantenerlos actualizados (en lugar de simplemente mantener actualizada la imagen del contenedor). Tampoco funcionará para comandos que se ejecutan específicamente en servicios dentro de contenedores (como el ejemplo de MySQL anterior).

¿Alguien tiene una solución para el problema anterior?Una solución queno es especificoa los ejemplos que di, pero un enfoque general que puede resolvereste tipo de error(ya sea completando con éxito, ejecutando todos los comandos o dando un error y deteniendo todos los comandos posteriores).

Actualizar:

Agregar declare -p vardespués de echo "after inside"las salidas:

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

Supongo que el comando de lectura termina leyendo del heredoc como señaló @muru en los comentarios. También puedo verlo si agrego echo "var=\$var"después echo "after inside", que imprime var=echo "after inside" >&2:. Así que ahora tengo que encontrar una manera de omitir esas lecturas del propio documento heredoc.

información relacionada