次の例を見てみましょう。
[user@user~]$ sudo docker run -d -e XYZ=123 ubuntu sleep 10000
2543e7235fa9
[user@user~]$ sudo docker exec 2543e7235fa9 echo test
test
[user@user~]$ sudo docker exec 2543e7235fa9 echo $XYZ
<empty row>
[user@user~]$ sudo docker exec -it 2543e7235fa9 bash
root@2543e7235fa9:/# echo $XYZ
123
<empty row>
代わりになぜ受けますか123
? bashを実行して入力した後に表示されるのはなぜですかXYZ=123
?
答え1
ここに欠けている2つのことは次のとおりです。
docker exec ... <command>
<command>
デフォルトでは、シェルで実行されず、シェル<command>
なしでコンテナでのみ実行されます。非対話型シェルの docker でコマンドを実行するには、次のようにします。
docker exec <container> bash -c '<command>'
複数の単語がある場合は、
<command>
コマンド全体を一重引用符または二重引用符で囲んで渡す必要がありますbash -c
。例えば
sudo docker exec 2543e7235fa9 bash -c 'echo $XYZ'
これを行うには、2つのシェルを持つことが重要です。
- 実行中のシェル
sudo docker exec ...
(「Shell A」と呼ばれる) - コンテナ内で実行されるシェル(「シェルB」と呼ばれる)
もしあなたならいいえシェルAのバックスラッシュエスケープまたは一重引用符
$
とシェルAは独自の値を挿入します$XYZ
(値がなくても空の文字列を返します)。したがって
XYZ=5
、シェルAにいる場合、あなたのシェルsudo docker exec 2543e7235fa9 echo $XYZ
はと同じですexec 2543e7235fa9 echo 5
(dockerにrunを指示しなかったため、シェルBもありませんbash -c ...
)。もしあなたならするエスケープまたは一重引用符を使用して
$
それをそのままシェルBに渡し、シェルBはその値を挿入します$XYZ
。- 実行中のシェル
つまり、次を使用します。
sudo docker exec 2543e7235fa9 bash -c 'echo $XYZ'
または
sudo docker exec 2543e7235fa9 bash -c "echo \$XYZ"
私の考えでは、一重引用符形式が何をしているのか、そしてほとんどの場合使用する必要があることを理解するのは簡単です。一重引用符内では変数の補間は発生しないため、コマンドはシェルBと同じように渡されます。
二重引用符形式は、シェルAからシェルBに変数を渡す必要がある場合に便利です。リテラルも渡す必要がある場合は、$
バックスラッシュエスケープを使用する必要があります。たとえば、シェルB echoシェルA$ABC
とそれ自体があります$XYZ
。
sudo docker exec 2543e7235fa9 bash -c "echo $ABC \$XYZ"
シェルA$ABC
が123で10
シェルB$XYZ
が123の場合、出力は次のようになります。
10 123
$XYZ
注:シェルBの開始ファイルの1つに定義されていない場合、またはdocker run -e XYZ=123
例で使用されている(または使用されていない-env-file
)場合以外は値はありません。
答え2
$XYZ
コマンドを実行するシェルによって拡張されるからですdocker exec
。$XYZ
文字列を入れるには引用符が必要です。
sudo docker exec ... echo \$XYZ
実際に誤解があります。パラメータが何で、シェルでどのように機能するかについてです。走るとき
any-command $XYZ
any-command
そんなことを見たことがありません$XYZ
。シェルはそれをそのシェルのパラメータの値に置き換えます。引数が指定されていないXYZ
か、引数が空であるため、シェルに送信する実際のコマンドラインは次のとおりです。
sudo docker exec 2543e7235fa9 echo