web-dev-qa-db-ja.com

Linux teeコマンドを終了する方法

Linuxマシンの電源がオンになっている限り実行されるbashスクリプトがあります。以下に示すように開始します。

( /mnt/apps/start.sh 2>&1 | tee /tmp/nginx/debug_log.log ) &

起動後、以下のようにps出力にteeコマンドが表示されます。

$ ps | grep tee
  418 root       0:02 tee /tmp/nginx/debug_log.log
3557 root       0:00 grep tee

teeが生成するログのサイズを監視し、ログが特定のサイズに達したときにteeコマンドを強制終了する関数があります。

monitor_debug_log_size() {
                ## Monitor the file size of the debug log to make sure it does not get too big
                while true; do
                                cecho r "CHECKING DEBUG LOG SIZE... "
                                debugLogSizeBytes=$(stat -c%s "/tmp/nginx/debug_log.log")
                                cecho r "DEBUG LOG SIZE: $debugLogSizeBytes"
                                if [ $((debugLogSizeBytes)) -gt 100000 ]; then
                                                cecho r "DEBUG LOG HAS GROWN TO LARGE... "
                                                sleep 3
                                                #rm -rf /tmp/nginx/debug_log.log 1>/dev/null 2>/dev/null
                                                kill -9 `pgrep -f tee`
                                fi
                                sleep 30
                done
}

驚いたことに、teeコマンドを強制終了すると、start.shインスタンスによっても強制終了されます。どうしてこれなの? teeコマンドを終了するにはどうすればよいのですか?ありがとう。

19
PhilBot

teeが終了すると、それ以上の出力を書き込もうとするまで、それを供給するコマンドは実行を続けます。次に、リーダーなしでパイプに書き込もうとするSIGPIPE(ほとんどのシステムでは13)を取得します。

スクリプトを変更してSIGPIPEをトラップし、適切なアクション(出力の書き込みを停止するなど)を実行すると、ティーが終了した後もスクリプトを続行できるはずです。


teeを強制終了するよりも、logrotatecopytruncateオプションとともに使用して、シンプル。

引用するにはlogrotate(8)

copytruncate

古いログファイルを移動してオプションで新しいログファイルを作成する代わりに、コピーの作成後に元のログファイルを切り捨てます。一部のプログラムにログファイルを閉じるように指示できないため、以前のログファイルに永久に書き込み(追加)し続ける可能性がある場合に使用できます。ファイルのコピーと切り捨ての間に非常に小さなタイムスライスがあるため、一部のログデータが失われる可能性があることに注意してください。このオプションを使用すると、古いログファイルがそのまま残るため、作成オプションは無効になります。

34
Wildcard

「なぜ」を説明する

つまり、書き込みが失敗した場合が原因でプログラムが終了した場合(デフォルト)、混乱が生じます。 find . | head -n 10を検討してください。findが必要な10行をすでに取得して続行した後、headが残りのハードドライブをスキャンし続けないようにします。

より良い方法:ロガー内部を回転させる

例として、teeをまったく使用しない次の例を検討してください。

#!/usr/bin/env bash

file=${1:-debug.log}                     # filename as 1st argument
max_size=${2:-100000}                    # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit  # Use GNU stat to retrieve size
exec >>"$file"                           # Open file for append

while IFS= read -r line; do              # read a line from stdin
  size=$(( size + ${#line} + 1 ))        # add line's length + 1 to our counter
  if (( size > max_size )); then         # and if it exceeds our maximum...
    mv -- "$file" "$file.old"            # ...rename the file away...
    exec >"$file"                        # ...and reopen a new file as stdout
    size=0                               # ...resetting our size counter
  fi
  printf '%s\n' "$line"                  # regardless, append to our current stdout
done

次のように実行した場合:

/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log

...これは、/tmp/nginx/debug_logに追加し、100KBを超えるコンテンツが存在する場合にファイルの名前を/tmp/nginx/debug_log.oldに変更することから始まります。ロガー自体がローテーションを行っているため、ローテーションが発生しても、パイプの破損、エラー、データ損失ウィンドウは発生しません。すべての行が1つのファイルまたは別のファイルに書き込まれます。

もちろん、これをネイティブbashに実装することは非効率的ですが、上記は例示的な例です。上記のロジックを実装する多数のプログラムが利用可能です。考慮してください:

  • svlogd 、Runitスイートのサービスロガー。
  • s6-log 、skanetスイートからアクティブに維持される代替。
  • multilog このプロセス監視および監視ツールのファミリーの祖父であるDJB Daemontoolsから。
3
Charles Duffy