하지만...

하지만...

출력이 로그 파일로 리디렉션되는 프로그램이 있습니다.

./my_app > log

때때로 (요청 시) 로그를 지우고(즉, 비우고) 다음과 같은 다양한 방법을 시도하고 싶습니다.

cat "" > log

그러나 원래 파이프가 중단되고 프로그램이 더 이상 출력을 로그 파일로 리디렉션하지 않는 것 같습니다.

이를 수행할 수 있는 방법이 있습니까?

고쳐 쓰다

출력을 생성하는 애플리케이션은 수정할 수 없습니다. stdout으로 인쇄하고 필요한 경우 확인하고 지울 수 있도록 로그에 저장하고 싶습니다. 하지만 애플리케이션을 다시 시작할 필요는 없습니다.

답변1

이 문제의 또 다른 형태는 로그가 정기적으로 순환되는 장기 실행 애플리케이션에서 발생합니다. 원본 로그(예: )를 이동 mv log.txt log.1하고 실제 로깅이 발생하기 직전에 동일한 이름의 파일로 교체하더라도 프로세스가 파일을 열어두면 쓰기가 종료됩니다 log.1(여전히 열려 있는 inode일 수 있으므로). 뭔가 하지도 마세요.

이를 처리하는 일반적인 방법(시스템 로거 자체는 이런 방식으로 작동함)은 로그를 닫고 다시 여는 프로세스에 신호 처리기를 구현하는 것입니다. 그런 다음 로그를 이동하거나 삭제(삭제)하려는 경우 즉시 해당 신호를 프로세스에 보냅니다.

다음은 bash의 간단한 데모입니다. 제 형편없는 쉘 기술을 용서해 주세요(그러나 모범 사례 등을 위해 이것을 편집하려면 먼저 기능을 이해하고 개정판을 테스트하십시오).앞으로귀하의 편집):

#!/bin/bash

trap sighandler INT

function sighandler () {
    touch log.txt
    exec &> log.txt
}

echo $BASHPID
exec &> log.txt

count=0;
while [ $count -lt 60 ]; do
    echo "$BASHPID Count is now $count"
    sleep 2
    ((count++))
done          

백그라운드로 분기하여 시작하십시오.

> ./test.sh &
12356

PID를 터미널에 보고한 다음 에 로깅을 시작합니다 log.txt. 이제 2분 동안 플레이할 수 있습니다. 몇 초 정도 기다렸다가 다음을 시도해 보세요.

> mv log.txt log.1 && kill -s 2 12356

간단한 것들도 kill -2 12356당신에게 도움이 될 수 있습니다. 신호 2는 SIGINT입니다(Ctrl-C가 수행하는 작업이기도 하므로 포그라운드에서 이 작업을 시도하고 다른 터미널에서 로그 파일을 이동하거나 삭제할 수 있음). 이는 trap포착되어야 합니다. 확인하다;

> cat log.1
12356 Count is now 0
12356 Count is now 1
12356 Count is now 2
12356 Count is now 3
12356 Count is now 4
12356 Count is now 5
12356 Count is now 6
12356 Count is now 7
12356 Count is now 8
12356 Count is now 9
12356 Count is now 10
12356 Count is now 11
12356 Count is now 12
12356 Count is now 13
12356 Count is now 14

log.txt이제 이동했음에도 불구하고 여전히 작성 중인지 확인해 보겠습니다.

> cat log.txt
12356 Count is now 15
12356 Count is now 16
12356 Count is now 17
12356 Count is now 18
12356 Count is now 19
12356 Count is now 20
12356 Count is now 21

중단된 부분부터 계속해서 시작됩니다. 기록을 남기고 싶지 않다면 로그를 삭제하여 삭제하세요.

> rm -f log.txt && kill -s 2 12356

확인하다:

> cat log.txt
12356 Count is now 29
12356 Count is now 30
12356 Count is now 31
12356 Count is now 32
12356 Count is now 33
12356 Count is now 34
12356 Count is now 35
12356 Count is now 36

아직도 계속되고 있습니다.

불행하게도 실행된 하위 프로세스에 대한 쉘 스크립트에서는 이 작업을 수행할 수 없습니다. 왜냐하면 bash의 자체 신호 처리기가 trap전경에 있으면 정지되고, 배경으로 분기하면 해당 신호 처리기를 재할당할 수 없기 때문입니다. 산출. 즉, 이것은 애플리케이션에서 구현해야 하는 것입니다.

하지만...

애플리케이션을 수정할 수 없는 경우(예: 애플리케이션을 작성하지 않았기 때문에)CLI 유틸리티중개자로 사용할 수 있습니다. 로그에 대한 파이프로 스크립트에서 간단한 버전을 구현할 수도 있습니다.

#!/bin/bash

trap sighandler INT

function sighandler () {
    touch log.txt
    exec 1> log.txt
}

echo "$0 $BASHPID"
exec 1> log.txt

count=0;
while read; do
    echo $REPLY
done  

그것을 이라고 부르자 pipetrap.sh. 이제 기록하려는 애플리케이션을 모방하여 테스트할 별도의 프로그램이 필요합니다.

#!/bin/bash

count=0
while [ $count -lt 60 ]; do
    echo "$BASHPID Count is now $count"
    sleep 2
    ((count++))
done           

그것은 다음과 같습니다 test.sh:

> (./test.sh | ./pipetrap.sh) &
./pipetrap.sh 15859

이는 PID가 서로 다른 두 개의 별도 프로세스입니다. 다음을 통해 어셈블 test.sh되는 출력을 삭제합니다 pipetrap.sh.

> rm -f log.txt && kill -s 2 15859

확인하다:

>cat log.txt
15858 Count is now 6
15858 Count is now 7
15858 Count is now 8

15858, 은 test.sh(는) 여전히 실행 중이며 출력을 기록하고 있습니다. 이 경우 애플리케이션을 수정할 필요가 없습니다.

답변2

긴 이야기 짧게

로그 파일 열기추가의모델:

cmd >> log

그런 다음 안전하게 잘라낼 수 있습니다.

: > log

세부 사항

Bourne과 같은 셸을 사용하면 쓰기 위해 파일을 여는 세 가지 주요 방법이 있습니다. 존재하다그냥 써( >),읽기+쓰기( <>) 또는추가의(및 쓰기 전용 >>) 모드.

처음 두 개에서는 커널이 현재 위치를 기억합니다(즉,파일 설명 열기, 파일을 연 파일 설명자에서 복사되거나 상속된 모든 파일 설명자가 공유하는 파일)이 파일에 입력됩니다.

이 작업을 수행할 때:

cmd > log

log~에 열려있다그냥 써쉘의 표준 출력 모드 cmd.

cmd(초기 프로세스는 쉘과 가능한 모든 하위 프로세스에 의해 생성됩니다.) 표준 출력에 쓸 때 현재 커서 위치에 씁니다.파일 설명 열기그들은 파일을 공유합니다.

예를 들어 cmd처음에 기록된 경우 zzz위치는 파일의 바이트 오프셋 4에 있고 다음에 cmd파일이나 해당 하위 항목이 기록될 때 데이터는 이 위치에 기록됩니다.

파일이 축소된 경우(예: 파일이 잘린 경우)

: > log

cmdwrites xxxx오프셋에 기록되고 4처음 3자는 NUL 문자로 대체됩니다.

$ exec 3> log # open file on fd 3.
$ printf zzz >&3
$ od -c log
0000000   z   z   z
0000003
$ printf aaaa >> log # other open file description -> different cursor
$ od -c log
0000000   z   z   z   a   a   a   a
0000007
$ printf bb >&3 # still write at the original position
$ od -c log
0000000   z   z   z   b   b   a   a
0000007
$ : > log
$ wc log
0 0 0 log
$ printf x >&3
$ od -c log
0000000  \0  \0  \0  \0  \0   x
0000006

즉, 쓰기 전용 모드로 열린 파일은 자를 수 없습니다(예:읽기+쓰기) 그렇게 하면 파일의 파일 설명자를 여는 프로세스에서 파일 시작 부분에 NUL 문자가 남게 됩니다(OS/X를 제외하고 이러한 문자는 일반적으로 디스크 공간을 차지하지 않고 희소 파일로 전환됩니다).

대신(대부분의 응용 프로그램이 로그 파일에 쓸 때 이 작업을 수행한다는 것을 알 수 있습니다) 다음을 수행해야 합니다.추가의모델:

cmd >> log

또는

: > log && cmd >> log

빈 파일로 시작하려는 경우.

추가 모드에서는 마지막 쓰기 위치에 관계없이 모든 쓰기가 파일 끝에 이루어집니다.

$ exec 4>> log
$ printf aa >&4
$ printf x >> log
$ printf bb >&4
$ od -c log
0000000   a   a   x   b   b
0000005
$ : > log
$ printf cc >&4
$ od -c log
0000000   c   c
0000002

또한 두 프로세스가 실수로 파일을 여는 경우(예를 들어 동일한 데몬의 두 인스턴스를 시작하는 경우) 출력이 서로 덮어쓰지 않는다는 점에서 더 안전합니다.

최신 버전의 Linux에서는 현재 위치와 파일 설명자가 열려 있는지 확인할 수 있습니다.추가의패턴은 다음을 통해 볼 수 있습니다 /proc/<pid>/fdinfo/<fd>.

$ cat /proc/self/fdinfo/4
pos:        2
flags:      0102001

또는 다음을 사용하여:

$ lsof +f G -p "$$" -ad 4
COMMAND  PID USER   FD   TYPE  FILE-FLAG DEVICE SIZE/OFF     NODE NAME
zsh     4870 root    4w   REG 0x8401;0x0 252,18        2 59431479 /home/chazelas/log
~# lsof +f g -p "$$" -ad 4
COMMAND  PID USER   FD   TYPE FILE-FLAG DEVICE SIZE/OFF     NODE NAME
zsh     4870 root    4w   REG   W,AP,LG 252,18        2 59431479 /home/chazelas/log

이 플래그는 다음에 해당합니다.산소..._ open시스템 호출에 전달된 플래그입니다.

$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01

( O_APPEND8진수로는 0x400 또는 02000입니다)

따라서 쉘은 (여기서 0100000은 이 질문과 관련이 없는 O_LARGEFILE임) 을 사용 하여 >>파일을 엽니다 .O_WRONLY|O_APPEND>O_WRONLY<>O_RDWR

다음을 수행하는 경우:

sudo lsof -nP +f g | grep ,AP

를 사용하여 연 파일을 검색하려면 O_APPEND현재 시스템에 쓰기 위해 열려 있는 대부분의 로그 파일을 찾을 수 있습니다.

답변3

내가 올바르게 이해했다면 tee이것은 합리적인 접근 방식처럼 보입니다.

$ ./myapp-that-echoes-the-date-every-second | tee log > /dev/null &
[1] 20519
$ head log
Thu Apr  3 11:29:34 EDT 2014
Thu Apr  3 11:29:35 EDT 2014
Thu Apr  3 11:29:36 EDT 2014
$ > log
$ head log
Thu Apr  3 11:29:40 EDT 2014
Thu Apr  3 11:29:41 EDT 2014
Thu Apr  3 11:29:42 EDT 2014

답변4

이 문제는 오랫동안 syslog(및 모든 변형)로 해결되었지만 특정 문제를 쉽게 해결할 수 있는 두 가지 도구가 있습니다.

이식성은 더 높지만 다용도는 떨어지는 첫 번째 솔루션은 로거(관리자의 도구 상자에 꼭 있어야 하는 것)입니다. 표준 입력을 시스템 로그에 복사하는 간단한 유틸리티입니다. (책임을 전가하고 파일 회전을 logrotate 및 syslog의 문제로 만들기)

두 번째로 더 훌륭하지만 이식성이 떨어지는 솔루션은 syslog-ng입니다. 이는 표준 syslog 소켓에서 로그 메시지를 받는 것 외에도 로거를 통해 출력을 필터링하는 프로그램을 실행할 수도 있습니다. (아직 이 기능을 사용해본 적은 없지만, 하고 싶은 일에는 딱 맞는 것 같습니다.)

관련 정보