수신중인 응용 프로그램을 종료하지 않고 Linux tee 명령을 종료하는 방법


19

Linux 컴퓨터의 전원이 켜져있는 한 bash 스크립트가 있습니다. 아래 그림과 같이 시작합니다.

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

lauches 후, 아래와 같이 ps 출력 에서 tee 명령을 볼 수 있습니다.

$ ps | grep tee
  418 root       0:02 tee /tmp/nginx/debug_log.log
3557 root       0:00 grep 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 명령을 끝내고 start.sh를 계속 실행하려면 어떻게해야합니까? 감사.

답변:


34

tee종료 되면 더 많은 출력을 쓰려고 시도 할 때까지 공급 명령이 계속 실행됩니다. 그런 다음 독자없이 파이프에 쓰려고 시도 할 때 SIGPIPE (대부분의 시스템에서 13 개)를 얻습니다.

스크립트를 수정하여 SIGPIPE를 트랩하고 적절한 조치 (예 : 출력 쓰기 중지)를 수행하면 티가 종료 된 후에도 스크립트를 계속 사용할 수 있습니다.


더 나은 방법 tee 은 전혀 죽이지 않고 단순성 옵션을 사용 logrotate하는 copytruncate것입니다.

인용 logrotate(8):

copytruncate

사본을 작성한 후 기존 로그 파일을 이동하고 선택적으로 새 로그 파일을 작성하는 대신 원본 로그 파일을 잘라냅니다. 일부 프로그램이 로그 파일을 닫으라고 지시 할 수 없어서 이전 로그 파일에 계속 기록 (추가) 될 수있는 경우에 사용할 수 있습니다. 파일 복사와 잘라 내기 사이에는 시간 분할이 매우 작으므로 일부 로깅 데이터가 손실 될 수 있습니다. 이 옵션을 사용하면 이전 로그 파일이 그대로 유지되므로 create 옵션이 적용되지 않습니다.


9
또한 사용하고자하는 것 tee -a에 대한 tee그렇지 않으면 티 같은 맥 OS 그것에 당신이 그것을 (절단 후 동일한 오프셋에서 파일로 작성과 스파 스 파일을 지원하지 않는 시스템에서 수행되며, 추가 모드에서 파일을 여는 의지 디스크 공간의 두 배를 차지하면서 해당 위치로 이어지는 파일 섹션을 다시 할당하십시오.
Stéphane Chazelas

4
다른 옵션은 logger -ssyslog가 로깅을 처리 하도록 파이프하는 것 입니다 ( -sstderr에도 인쇄).
Stéphane Chazelas

1
일에 대한 logrotate. 훌륭한 프로그램
Dmitry Kudriavtsev

2
또는 로거 대신 systemd 및 journald, systemd-cat을 사용하는 시스템에서. 그런 다음 많은 출력 필터링 및 회전을 무료로 얻을 수 있습니다.
Zan Lynx

3

"왜"를 설명

한마디로 : 쓰기 실패로 인해 프로그램이 종료 되지 않으면 (기본적으로) 엉망이됩니다. 고려하십시오 find . | head -n 10- 필요한 10 줄을 이미 가져 와서 진행 find한 후에 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

... 이것은에 추가하여 시작하고 100KB가 넘는 내용이 존재할 때 /tmp/nginx/debug_log파일의 이름을 바꿉니다 /tmp/nginx/debug_log.old. 로거 자체가 회전을 수행하기 때문에 회전이 발생할 때 파이프가 끊어지고 오류가 없으며 데이터 손실 창이 없습니다. 모든 행이 한 파일에 작성됩니다.

물론 네이티브 bash에서 이것을 구현하는 것은 비효율적이지만 위의 예는 예시입니다. 위의 논리를 구현할 수있는 수많은 프로그램이 있습니다. 치다:

  • svlogdRunit 제품군의 서비스 로거입니다.
  • s6-log, skanet 제품군에서 적극적으로 유지 관리되는 대안입니다.
  • multilog DJB Daemontools, 프로세스 감독 및 모니터링 툴링 제품군의 손자.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.