Команда чтения пропускает последующие инструкции в HEREDOC - Bash + Docker

Команда чтения пропускает последующие инструкции в HEREDOC - Bash + Docker

У меня возникли проблемы со случаем, который я рассматриваю как ошибку в работе оболочки или bash, при которой запуск неинтерактивной команды, предоставленной из heredoc (возможно, также из файла, я не проверял) и read(или аналогичной) команды в heredoc, приводит к тому, что код после readкоманды становитсяпроигнорировано, и исполнение заканчиваетсябез ошибок, выполняя командыпослекоманда, запускающая heredoc.

А точнее, я запускаю код в контейнере Docker, который служит набором инструментов для нескольких утилит Linux, и эта проблема делает код на самом деле небезопасным в том смысле, что я не могу быть уверен, что он будет работать так, как я ожидаю.

Пример проблемы можно увидеть ниже:

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

Я ожидал, что приведенный выше код либо выполнит все эхо-сообщения и завершится успешно, либо выдаст ошибку в readкоманде и завершится с ошибкой.

К сожалению, вывод приведенного выше кода таков:

before outside
before inside
after outside

По сути, он проигнорировал то, что было после readкоманды., возможно, потому, что в команде есть readинструкция, которая не выделяет псевдотерминал ( docker run -itвыделяет псевдотерминал, но не может выполнить приведенный выше код из-за heredoc, который передается в команду, вместо этого выдается ошибка: the input device is not a TTY).

Если я удалю 2, set -eou pipefailу меня будет та же проблема, даже при использовании read 'var' ||:, поэтому я не думаю, что это связано с (одним изгочаиз) set -e.

Пример ожидаемого результата выглядит следующим образом:

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

Который завершается успешно и печатает:

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

Или:

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

Который заканчивается ошибкой и выводит:

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

Для меня было бы нормально, если бы readкоманда была просто пропущена (например, с пустым значением в качестве входных данных) и все команды после нее были бы выполнены, даже те, что в heredoc, или чтобы она выдавала ошибку и немедленно останавливала выполнение (если я не игнорирую ошибку в команде docker).

Выше был всего лишь пример, в реальном случае все может быть намного хуже, поскольку readкоманда (или подобная) может быть вызвана не напрямую, а внутри команды и только при некоторых условиях. Например:

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

Приведенный выше код может показаться правильным, но если пароль пуст, он попытается прочитать его из stdin, что приведет к проблеме в первом примере, пропуская some_important_command_2, но запуск some_important_command_after_2этого кода должен выполняться только после some_important_command_2.

Приведенный выше пример MySQL также был всего лишь примером, в этом случае я могу проверить, является ли пароль пустым, и обработать его.Реальная проблема в том, что я не могу определить, может ли эта проблема возникнуть внутри кода, и не вижу безопасного способа ее избежать., помимо остановки использования контейнера docker toolbox и установки всех утилит и прочего внутри всех хостов, а также поддержания их в актуальном состоянии (вместо того, чтобы просто поддерживать в актуальном состоянии образ контейнера). Это также не будет работать для команд, которые запускаются специально в службах внутри контейнеров (как в примере mysql выше).

У кого-нибудь есть решение вышеуказанной проблемы?Решение, котороене является конкретнымк примерам, которые я привел, но общий подход, который может решитьэтот тип ошибки(либо успешно завершив выполнение всех команд, либо выдав ошибку и остановив все последующие команды).

Обновлять:

Добавляем declare -p varпосле echo "after inside"выходов:

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

Я предполагаю, что команда read в конечном итоге считывает heredoc, как указал @muru в комментариях. Я также могу увидеть это, если добавлю echo "var=\$var"после echo "after inside", что выведет: var=echo "after inside" >&2. Так что теперь мне нужно найти способ пропустить эти чтения из самого heredoc.

Связанный контент