read
問題が発生しました。シェルやbashの動作方法にバグがあるようです。ここでは、heredoc(おそらくファイルで提供されているかもしれませんがテストされていない)および(または同様の)で提供される非対話型コマンドを実行します。 )heredocのコマンドのためにread
コマンドが生成されました。後ろのコードは次のとおりです。無視される、実行が終了しますエラーなし、注文の実行後ろにheredoc コマンドを実行します。
具体的に言えば、複数のLinuxユーティリティのツールボックスとして機能するDockerコンテナでコードを実行しています。
この問題の例は次のとおりです。
#!/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
コマンドに疑似ttyを割り当てないように指示することがあるからです(疑似docker run -it
ttyを割り当てますが、コマンドの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
スキップして(たとえば、null値を入力として使用します)、コマンド以降のすべてのコマンドが実行された場合(区切り文書のコマンドを含む)エラーが発生し、すぐに実行が停止します(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ツールボックスコンテナの使用を中止し、すべてのホストにすべてのユーティリティやその他のアイテムをインストールして最新の状態に保ちます(コンテナイメージを最新の状態に保つのではなく)。また、上記のmysqlの例のように、コンテナ内のサービス内で具体的に実行されるコマンドでは機能しません。
上記の問題に対する解決策を持っている人はいますか?解決策特にない例を挙げていますが、解決できる一般的な方法があります。この種のエラー(成功的に完了するか、すべてのコマンドを実行するか、エラーを発生させ、その後のすべてのコマンドを停止することによって)
修正する:
追加declare -p var
後の出力echo "after inside"
:
before outside
before inside
declare -- var="echo \"after inside\" >&2"
after outside
@muruがコメントで指摘したように、読み取りコマンドは区切り文書からの読み取りで終わるようです。echo "var=\$var"
後ろに追加すると、以下が印刷され、私も見ることができますecho "after inside"
。var=echo "after inside" >&2
ここで、区切られた文書自体でその読み取りをスキップする方法を見つける必要があります。