「パッチ」スクリプトを実行するボードがあります。パッチスクリプトは常にバックグラウンドで実行され、次の擬似コードを実行するシェルスクリプトです。
while true; do
# checks if a patch tar file exists and if yes then do patching
sleep 10
done
このスクリプトは /opt/patch.sh にあり、SystemV init スクリプトによって開始されます。
問題は、スクリプトがtarを見つけたらそれを抽出し、内部に次のシェルスクリプトがあることです。パッチファイルこれはtar関連コンテンツです。
スクリプトが入っているとき/opt/patch.shtarを見つけるには:
tar -xf /opt/update.tar -C /mnt/update
mv /mnt/update/patch.sh /opt/patch.sh
exec /opt/patch.sh
自分を別のスクリプトに置き換えて、同じ場所で実行します。これを行うのに問題がありますか?
答え1
ファイルが内部書き込みに置き換えられると(inodeは変更されません)、ファイルを開いたプロセスはファイルを読み取ると新しいデータを表示します。古いファイルのリンクを解除し、同じ名前の新しいファイルを作成して古いファイルを置き換えると、inode番号が変更され、ファイルを開いたままにしたすべてのプロセスはまだinode番号を保持します。古い文書。
mv
ファイルシステム間で移動が発生したかどうかに応じて、2つの操作のいずれかを実行できます。まったく新しいファイルを入手するには、まず元のファイルのリンクを解除するか、名前を変更します。このような:
mv /opt/patch.sh /opt/patch.sh.old # or rm
mv /mnt/update/patch.sh /opt/patch.sh
これにより、移動後も実行中のシェルは、古いデータのファイルハンドルを保持し続けます。
つまり、私がテストした限り、Bashはループを実行する前にループ全体を読み取るので、デフォルトファイルへの変更は、実行がループ内に残っている限り、実行中のスクリプトを変更しません。 (フルループに影響を与えるリダイレクトが最後にある可能性があるため、実行する前にループ全体を読み取る必要があります。)
ループを終了した後、Bashは読み取りポインタをループが終了した位置に戻し、ループが終了した後に位置から入力ファイルを読み続けます。
スクリプトで定義されているすべての関数もメモリにロードされるため、スクリプトの基本ロジックを関数に入れて最後に呼び出すだけで、ファイルの変更からスクリプトが非常に安全になります。
#!/bin/sh
main() {
do_stuff
exit
}
main
とにかく、スクリプトがオーバーライドされると、何が起こるかをテストするのは難しくありません。
$ cat > old.sh <<'EOF'
#!/bin/bash
for i in 1 2 3 4 ; do
# rm old.sh
cat new.sh > old.sh
sleep 1
echo $i
done
echo will this be reached?
EOF
$ cat > new.sh <<'EOF'
#!/bin/bash
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF
$ bash old.sh
コメントアウトすると、rm old.sh
スクリプトは内部で変更されます。コメントがない場合は、新しいファイルが生成されます。 (この例は、new.sh
より大きいよりも部分的に依存しますold.sh
。まるでそれが短いように、シェルはループの後に新しいスクリプトの終わりを過ぎて読みます。)
答え2
以前にこの問題が発生したことがあり、これが問題になる可能性があることを確認できます。私の場合、回帰スクリプトは最初にgit pullを実行し、おそらく実行が開始された後に更新され、問題が発生したようです。
問題は通常、シェルが戻って解釈する行がさらにあるかどうかを確認することです。必要なコードがループ内にあってもエラーが発生する可能性があります。これを防ぐには、次の構造を使用します。この投稿。
答え3
自動的に実行され、自動的に変更されるスクリプト?これは良い考えではありません。
より良い解決策は、最小限の機能(つまり、新しいバージョンをインストールして定期的に呼び出すスレーブスクリプト)でスタブデーモンを作成することです。次のようなもの...(テストされていません)
while true; do
# check if a patch tar file exists and if yes then do patching
if [ -f "$PATCH" ]; then
( cd /usr/local/mydaemon \
&& tar -xzf "$PATCH" \
&& rm -f "$PATCH" ) \
|| exit -1
fi
$SCRIPT
sleep 10
done