install.sh
デフォルトでは、次のスクリプトがあります。
#!/bin/bash
if [[ ! -f "/usr/bin/jq" ]]; then
apt-get update && apt-get install -y jq
fi
echo $(date) >> install.log
サーバーに置き、次のように実行すると:
curl -s0 https://myserver.com/install.sh | bash
クレイジーapt-get
出力の後echo
、最後の行を実行するのではなく、その行を出力echo $(date) >> test.log
として印刷します。一方、install.sh
ディスクに保存して実行すると、./install.sh
期待どおりに機能します。エコラインを実行してinstall.log
追加します。
問題をさらに再現するために、次のようにローカルで実行しました。
cat install.sh | bash
また、同じ問題があります。
apt-get remove jq
各テストの前に手動で実行してください。インストールすると、jq
両方が期待どおりに動作します。それでは、ダウンロードで実行するのとローカルファイルで実行するのはなぜ違いますか?
この問題を説明するために短いビデオを記録しました。https://www.youtube.com/watch?v=lYvGXI7AibA
ベストアンサー1
通常bash
、ファイル(bash foo
例bash <foo
:.しかし、今はapt-get
ユーザーに尋ねたいコマンド()を起動し、STDINを使用してそれを行います。
だから奇妙なことが起こります。 bashはSTDINからコマンドを読み込み、1つずつ実行します。これで、コマンドの1つがSTDINから読み取られ、ファイルの次の行が読み込まれます。その後、bashはSTDINから次の行を読み取るので、他のコマンドがすでに読み込んだ1つのコマンドをスキップします。
この小さなスクリプトは何が起こっているのかを示しています。
echo "hello"
read -p "how do you do? "
echo "I understand"
echo "you are '$REPLY'."
echo "bye"
ファイルに保存し、bash -x foo
まずasを実行してからasを実行しますbash -x <foo
。
あなたの場合でも同じことが起こります。
1つの解決策は、プロセス置換を使用することです。
bash -x <(cat foo)
またはあなたの場合は単に:
bash <(curl -s0 https://myserver.com/install.sh)
いくつかの注意:
シェルスクリプトが奇妙なことをするたびにbash -x
何が起こっているかを確認するために使用します。
書くcat foo| ...
ことが呼ばれる猫に役に立たない用途。リダイレクトを使用できます。