1. ホーム
  2. perl

[解決済み] unixで任意のスクリプトをデーモン化するには?

2023-02-05 20:29:20

質問

私は、任意の一般的なスクリプトやコマンドを デーモン .

よくあるケースが2つあるので、対処していきたいと思います。

  1. 永遠に実行されるはずのスクリプトがあります。 もし死ぬことがあったら (または再起動したら)、再起動します。 同時に 2 つのコピーを実行させないようにします (コピーがすでに実行されている場合は検出し、その場合は起動しないようにします)。

  2. 永遠に繰り返し実行し続けたい簡単なスクリプトまたはコマンド ライン コマンドがあります (実行の間に短い休止時間があります)。 繰り返しますが、スクリプトの 2 つのコピーを同時に実行することを許可してはいけません。

もちろん、ケース 2 のスクリプトの周りに "while(true)" ループを書き、ケース 1 の解決策を適用することは簡単ですが、より一般的な解決策は、ケース 1 のスクリプトにも適用されるため、直接ケース 2 を解決するだけです (スクリプトが決して死ぬことを意図していない場合は、単に短いか休止しないようにしたい場合があります (もちろん、スクリプトが本当に は決して死なないのであれば、一時停止は実際には重要ではありません)。

解決策は、たとえば、既存のスクリプトにファイルロックコードや PID 記録を追加するようなものではないことに注意してください。

より具体的には、私は次のように実行できるプログラム "daemonize" が欲しいです。

% daemonize myscript arg1 arg2

とか、例えば

% daemonize 'echo `date` >> /tmp/times.txt'

とすると、times.txt に追加される日付のリストがどんどん増えていきます。(上記のケース1のように、daemonizeへの引数が永遠に実行されるスクリプトである場合、daemonizeはまだ正しいことを行い、必要なときにそれを再起動することに注意してください)。 それから私は、上記のようなコマンドを .login に置き、毎時または毎分 (それが予期せず死ぬことをどの程度心配しているかに依存) にそれをクーロンすることができました。

注意: デーモン化スクリプトは、同じコマンド文字列が再びデーモン化された場合、2番目のコピーを起動しないように、デーモン化しているコマンド文字列を記憶する必要があります。

また、ソリューションは理想的には OS X と Linux の両方で動作する必要がありますが、どちらか一方のためのソリューションも歓迎します。

EDIT: もしあなたがそれを sudo daemonize myscript myargs .

(私の考え方が間違っていたり、手っ取り早い部分的な解決策があれば、それもぜひ教えてください)


追記:一応、役に立ちます。 はこちらです。 を参照してください。

そして この の回答には、任意のスクリプトを手早く悪者にするための便利なイディオムがあります。

どのように解決するのですか?

Unixでは、nohupと&演算子を使えば、どんな実行ファイルでもデーモン化することができます。

nohup yourScript.sh script args&

nohupコマンドは、スクリプトを殺すことなくシェルセッションをシャットダウンすることができ、一方&はスクリプトをバックグラウンドに置き、セッションを継続するためのシェルプロンプトを取得します。このコマンドの唯一の小さな問題は、標準出力と標準エラーが両方とも ./nohup.out に送られるため、この方法で複数のスクリプトを起動した場合、それらの出力が絡み合ってしまうことです。より良いコマンドは、次のようになります。

nohup yourScript.sh script args >script.out 2>script.error&

これは、標準出力はあなたが選んだファイルに、標準エラーはあなたが選んだ別のファイルに送ります。もし、標準出力と標準エラーの両方に一つのファイルを使いたい場合は、これを使うことができます。

nohup yourScript.sh script args >script.out 2>&1 &

2>&1 は、標準エラー(ファイル記述子2)を標準出力(ファイル記述子1)と同じファイルにリダイレクトするようにシェルに指示します。

コマンドを一度だけ実行し、終了したら再起動させるには、このスクリプトを使用することができます。

#!/bin/bash

if [[ $# < 1 ]]; then
    echo "Name of pid file not given."
    exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
    echo "No command given."
    exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
    ps -p $PID >/dev/null 2>&1
    if [[ $? = 0 ]]; then
        echo "Command $1 already running."
        exit
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
    $COMMAND "$@"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

第一引数は使用するpidファイル名です。第2引数はコマンドです。そして、それ以外の引数はコマンドの引数です。

このスクリプトに restart.sh という名前を付けると、このように呼び出されます。

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &