無限ループシェルスクリプトのメモリ使用量

無限ループシェルスクリプトのメモリ使用量

そのため、次のようにMySQLデータベースを更新するためのシェルスクリプトがあります。

#!/bin/sh
mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
sleep 5
sh $0

5秒間スリープ状態になり、sh $0ユーザーの介入なしにスクリプトを無制限に再実行します。しかし、私の質問はメモリに関するものです。

私はシェルスクリプトに最初に触れましたが、これはループ内のメモリがゆっくりと蓄積する方法ですか?リモートサーバーはメモリを回復しますか、それともスクリプトは最終的にカットオフポイントに到達しますか? (それともメモリリークによってクラッシュが発生しますか?)

答え1

これはループではなく、再帰的であり、時間の経過とともにメモリが直線的に増加するため、望ましくありません。

一定のメモリ使用量を持つループが必要な場合は、次のようにできます。

#!/bin/sh
while 1; do
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
done

答え2

シェルによって異なります。一部はテールコールの最適化を実行し、一部はそうではありません。を実行して簡単にテストできますSHELL -c 'ps $$'。それ自体が表示されると、psシェルは同じプロセスで最後のコマンドを実行しました。シェルが表示されると、psシェルは最後のコマンド以外のサブプロセスの最後のコマンドを実行します。

$ for s in dash bash mksh ksh zsh; do echo -n "$s "; $s -c 'ps -o comm= $$'; done 
dash dash
bash ps
mksh mksh
ksh ps
zsh ps

したがって、bash、ksh、zshはtail callの最適化を実行しますが、dashとmkshはそうではありません。

テール呼び出しの最適化は、スクリプトの最後のコマンドに対してのみ実行できます。たとえば、アクティブなトラップがある場合、トラップがトリガーされるとシェルが後ろにある必要があるため、テールコールではありません。

execコマンドの前に貼り付けることで、尾の呼び出しを強制することができます。組み込みコマンドは、exec同じプロセスで指定されたコマンドを実行します。シェルが消えるので、スクリプトの他のコマンドは実行されません。

再帰はシェルスクリプトでは慣用的ではありません。ループを使用する方がより慣用的です。

#!/bin/sh
while true; do
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
done

sleepまたは、シグナルによってコマンドが終了したときにスクリプトを終了させるには、次のようにします。

#!/bin/sh
while
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
do
  :
done

mysqlまたは、失敗した場合にスクリプトを終了するには、次のようにします。

#!/bin/sh
while
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
do
  sleep 5
done

関連情報