1

私はシェルスクリプトに関して非常に独特な問題に直面しています。

これがシナリオです

Script1(バックグラウンドでスポーン)-> Script2

Script2には次のコードがあります

function check_log()
{
    logfile=$1
    tail -5f ${logfile} | while read line
    do
      echo $line
      if echo $line|grep "${triggerword}";then
        echo "Logout completion detected"
        start_leaks_detection
        triggerwordfound=true
        echo "Leaks detection complete"
      fi
      if $triggerwordfound;then
        echo "Trigger word found and processing complete.Exiting"
        break
      fi

    done
        echo "Outside loop"
        exit 0

}

check_log "/tmp/somefile.log" "Logout detected"

ここで、whileループの中断は役に立ちません。「ログアウト完了が検出されました」と「リーク検出が完了しました」がstdoutにエコーされているのがわかりますが、文字列「outsideloop」はエコーされていません。

tail -fこれはサブシェルの作成と関係があると思います。私がやりたいのは、そのサブシェルを終了し、Script2を終了して、制御をScript1に戻すことです。

誰かがこれを行う方法に光を当てることができますか?

4

3 に答える 3

3

while ループにパイプする代わりに、次の形式を使用します。

while read line
do
   # put loop body here
done < <(tail -5f ${logfile})
于 2012-12-18T15:13:36.877 に答える
1

まったく同じではありませんが、これを試してください (起動時にログ ファイルの先頭をスキップしません)。

triggerwordfound=
while [ -z "$triggerwordfound" ]; do
    while read line; do
        echo $line
        if echo $line|grep "${triggerword}";then
            echo "Logout completion detected"
            start_leaks_detection
            triggerwordfound=true
            echo "Leaks detection complete"
        fi
    done
done < "$logfile"
echo "Outside loop"

二重ループは、実質的に と同じことを行いtail -fます。

于 2012-12-18T16:54:38.000 に答える
0

関数はある意味では機能しますが、トリガー ワードが見つかったに別の行がファイルに書き込まれるまで、機能していることに気付かないでしょう。これtail -5 -fは、通常、ファイルの最後の 5 行すべてを 1 回の呼び出しでパイプに書き込みwrite()、新しい行をすべて 1 回の呼び出しで書き続けることができるためSIGPIPEです。ループが終了しました。while

したがって、ファイルが定期的に大きくなる場合は問題はないはずですが、トリガー ワードが書き込まれた直後にファイルの成長が止まることがより一般的である場合は、ウォッチャー スクリプトも新しい出力が書き込まれるまでハングします。ファイルに。

つまり、パイプに未読のデータがバッファリングされていても、パイプが閉じられたときにすぐに送信されるのではなく、パイプで後続のデータが試行されたSIGPIPEときにのみ送信されます。write()

これは非常に簡単に証明できます。このコマンドは、手動で中断するか、ファイルにもう 1 バイト書き込むまで終了しません (ファイルの末尾がパイプ サイズのバッファーよりも小さい場合)。

tail -f some_large_file | read one

ただし、テールにパイプへの複数の書き込みを強制し、最後の書き込みの前にリーダーが終了するようにすると、すべてが期待どおりに機能します。

tail -c 1000000 some_large_file | read one

残念ながら、特定のシステムでパイプ バッファーのサイズを検出することは必ずしも容易ではありません。また、ファイル内に既にパイプ バッファーの値以上のデータがあり、トリガー ワードが既にファイル内で、ファイルの終わりから少なくともパイプ バッファーのサイズ バイト。

残念ながらtail -F(これはおそらく代わりに使用する必要があります-f)は、5秒ごとにゼロバイトを書き込もうとはしません。そうしないと、より効率的な方法で問題を解決できる可能性があります。

tailまた、 の使用に固執する場合-1は、少なくとも将来のイベントを検出するにはおそらく十分です。

ところで、これはわずかに改善された実装ですが、tailおそらくそれがおそらく最良のオプションだと思うので、まだ使用しています(いつでも定期的なマーカー行をログに追加するcronか、同様のものを使用できます(ほとんどのsyslogd実装には組み込みのマーク機能もあります))。マーカーの期間内に戻ります):

check_log ()
{
        tail -1 -F "$1" | while read line; do
                case "$line" in
                *"${2:-SOMETHING_IMPOSSIBLE_THAT_CANNOT_MATCH}"*)
                        echo "Found trigger word"
                        break
                        ;;
                esac
        done
}

echoステートメントを、トリガー フレーズが読み取られたときに必要な処理に置き換えます。

于 2012-12-18T21:22:51.763 に答える