로그 파일에서 마지막 50 줄을 유지하는 방법


21

매분마다 온도를 저장하는 파일에 마지막 50 줄을 유지하려고합니다. 나는이 명령을 사용했다 :

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

그러나 결과는 빈 테스트 파일입니다. 테스트 파일의 마지막 50 줄을 나열하고 테스트 파일에 삽입 할 것이라고 생각했습니다. 이 명령을 사용할 때 :

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

잘 작동합니다. test2 파일에는 50 줄이 있습니다.

아무도 문제가 어디 있는지 설명 할 수 있습니까?


2
rrdtool과 같은 것이 시간이 지남에 따라 N 개의 레코드 (다른 통계 중)를 유지하는 데 더 적합 할 수 있습니다.
thrig


2
클래식 잘림 문제
haylem

파이썬을 사용하여 로그를 생성하는 경우 logging모듈을 살펴 봐야 합니다
Wayne Werner

답변:


29

문제는 명령을 실행하기 전에 쉘이 명령 파이프 라인을 설정하고 있다는 것입니다. "입력 및 출력"의 문제는 아닙니다. 파일의 내용이 이미 테일이 실행되기 전에 이미 사라졌기 때문입니다. 그것은 다음과 같습니다 :

  1. 쉘은 >출력을 위해 출력 파일을 열어서 잘 립니다.
  2. 쉘은 그 출력에 파일 디스크립터 1 (stdout)이 사용되도록 설정합니다.
  3. 쉘이 실행 tail됩니다.
  4. tail달리고, 열리고 /home/pi/Documents/test아무것도 발견되지 않습니다.

다양한 솔루션이 있지만 문제의 핵심은 실제로 무엇이 잘못되고 있으며 왜 그런지 이해하는 것입니다.

이것은 당신이 찾고있는 것을 만들어 낼 것입니다.

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

설명 :

  • $() 실행되는 명령 대체라고합니다. tail -n 50 /home/pi/Documents/test
  • 따옴표는 출력에서 ​​줄 바꿈을 유지합니다.
  • > /home/pi/Documents/test출력을 echo "$(tail -n 50 /home/pi/Documents/test)"동일한 파일로 리디렉션 합니다.

잘 작동합니다 감사합니다! 질문이 하나 더 있습니다. 절차가 단계별로 어떻게 작동하는지 설명해 주시겠습니까?
dorinand

1
그러나 왜 귀하의 경우 bash가 먼저 수행하지 않습니까? bash가 명령을 처리하는 방법을 이해하지 못합니다. 아무도 설명 할 수 있습니까?
dorinand

1
>는 echo 명령에 있으므로 echo 명령이 실행될 때 실행됩니다. 쓰기 전에는 실행할 수 없습니다. 변수 대체는 명령을 작성하는 것입니다. 중첩 된 명령을 실행하고 값을 대체하여 echo 명령을 작성합니다.
jobermark

50 대신 5000 줄을 사용하여 44GB 로그 파일에 동일한 것을 사용하려고하면 오류가 발생합니다bash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon

8

파일을 먼저 지우는 파일 리디렉션에 대한 또 다른 해결책 spongemoreutils다음과 같이 packge 에서 사용 하는 것입니다.

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

6

배쉬가와 재 처리하기 때문입니다 >파일의 내용을 삭제, 첫 번째. 그런 다음 명령을 실행합니다. 사용했다 >>, 지난 50 개 라인은 파일에 현재 무엇의 끝에 추가됩니다. 이 경우, 같은 50 개 라인 두 번 반복해야 것입니다.

다른 파일로 리디렉션 할 때 예상대로 명령이 작동합니다. 여기에 같은 이름의 파일에 파일의 마지막 50 줄을 작성하는 한 가지 방법은 다음과 같습니다

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

이것은 먼저 사용하여 이동 임시 파일로 지난 50 선을 기록 mv원본 파일을 대체 할 수 있습니다.

코멘트에서 언급 한 바와 같이 파일이 여전히 열려있는 경우,이 작동하지 않습니다. 파일을 이동하면 새로운 아이 노드를 만들고 소유권과 권한을 변경할 수 있습니다. 더 좋은 방법이 될 것이다 임시 파일을 사용하여이 작업을 수행합니다 :

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

때마다이 내용을 덮어 쓸 것입니다 발생하지만 임시 파일도 제거 할 수있다.


고맙습니다. 당신은 나에게 무엇을 실행 비난 단계별로 설명해 주시겠습니까? 나는 그것이 어떻게 작동하는지 상상할 수 없다.
dorinand

tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
스티브

1
로그 파일은 로깅 프로세스에 의해 여전히 열려있는 경우이하지 않습니다 작업 (원본에 로깅을 계속하는 파일을 삭제)합니다. 임시 파일 + 움직임 (모든 하드 링크를 깨는) 새로운 아이 노드의 결과, 그리고 아마도 다른 소유자 또는 파마. tail ... > temp ; cat temp > orig ; rm -f temp공장.
CAS

4

당신이 쉘 리디렉션의 주요 문제를 본 적이 있기 때문에, 여기에 마지막 50 줄에 파일을 치기하는 다른 방법입니다 :

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

하드 작업은 함께 나오지도 (GNU)에 의해 수행되는 -i임시 파일에 출력을 생성하여 내부적으로 작동하는 "내부 편집"기능. 라인의 나머지 부분, 즉,의 나오지도 작동을 위해 수학을 설정 :

  1. 파일의 줄을 세고 ( wc) 50을 뺍니다. 에 할당하십시오 n.
  2. 경우 n 긍정적이고, n을 삭제 라인 1에 나오지 명령을 실행합니다.

4
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printf명령을 한 줄에 하나씩 파이프하는 데 사용됩니다 ed. ed명령은 다음과 같습니다

  • 1,$-50d -마지막 50 줄을 제외하고 모두 삭제
  • w -수정 된 파일을 디스크에 다시 쓴다

경로 재 지정이 없으므로 쉘은 출력 파일을 읽기 전에 출력 파일을 겹쳐 쓸 수 없습니다.

또한 대부분의 "in-place"편집 형식 (일반적으로 임시 파일을 만든 다음 원본 이름을 변경하여 "in-place"편집 만 시뮬레이션)과 달리 ed실제로 원본 파일을 편집하므로 동일한 inode ( 소유자, 그룹 및 권한-tempfile + mv는 항상 inode를 변경하고 상황에 따라 다른 설정을 변경할 있습니다.


4

약간 다른 트랙에서는 logrotate(8)정기적으로 로그 파일을 증분 이름이 지정된 파일로 백업 한 다음 이전 파일을 삭제하는 데 사용할 수 있습니다.

이것이 메인 시스템 로그 파일이 너무 길어지지 않도록 관리하는 방법입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.