로그 파일의 마지막 n 줄만 어떻게 유지합니까?


18

내가 작성한 스크립트는 무언가를 수행하고 결국 자체 로그 파일에 몇 줄을 추가합니다. 로그 파일의 마지막 n 줄 (예 : 1000 줄) 만 유지하고 싶습니다. 다음과 같은 방법으로 스크립트 끝에서 수행 할 수 있습니다.

tail -n 1000 myscript.log > myscript.log.tmp
mv -f myscript.log.tmp myscript.log

그러나 더 깨끗하고 우아한 해결책이 있습니까? 아마도 하나의 명령으로 달성했을까요?


logrotate는 우아한 솔루션입니다
Ipor Sircer

1
나는 그것을 생각했지만, logrotate 구성은 스크립트 자체보다 더 길 것입니다 ...
dr01

logrotate가 과도하게 사용되면 솔루션은 거의 우아합니다. sed / awk를 사용하면 한 줄로 수행 할 수 있지만 내부적으로 임시 파일이 없으면 더 효율적이지 않고 읽기 어려울 수 있습니다.
kba는 Monica

답변:


28

이와 같이 가능하지만 다른 사람들이 말했듯이 가장 안전한 옵션은 새 파일을 생성 한 다음 해당 파일을 이동하여 원본을 덮어 쓰는 것입니다.

아래 방법은 행을 BASH에로드하므로의 행 수에 따라 tail로그 행의 내용을 저장하는 로컬 셸의 메모리 사용에 영향을 미칩니다.

아래는 또한 BASH 평가 동작으로 인해 로그 파일 끝에 빈 줄이 있으면 제거 "$(tail -1000 test.log)"하므로 모든 시나리오에서 실제로 100 % 정확한 잘림을 제공하지는 않지만 상황에 따라 충분할 수 있습니다.

$ wc -l myscript.log
475494 myscript.log

$ echo "$(tail -1000 myscript.log)" > myscript.log

$ wc -l myscript.log
1000 myscript.log

똑똑한. 추가 도구를 설치할 필요가 없으므로 이것을 허용 된 답변으로 표시했습니다. 귀하와 @ John1024의 답변을 모두 수락 할 수 있기를 바랍니다.
dr01

당신의 전화. 나는 그것에 대해 몰랐기 때문에 스폰지 솔루션을 상향 조정했으며 빈 로그 라인을 엉망으로 만들지 않습니다. 이 솔루션은 로그 파일 내용에 따라이를 수행 할 수 있습니다.
parkamark

이 솔루션에는 경쟁 조건이 있습니다. 운이 좋지 않은 경우 파일에서 경로 재 지정은 파일을 읽기 전에 발생하며 빈 파일이됩니다.
Coroos

21

sponge이 경우를 위해 유틸리티 가 설계되었습니다. 설치 한 경우 두 줄을 쓸 수 있습니다.

tail -n 1000 myscript.log | sponge myscript.log

일반적으로 파일을 쓰는 동시에 파일을 읽는 것은 신뢰할 수 없습니다. 읽은 후에 파이프를 종료 spongemyscript.log때까지 쓰지 않음으로써이를 해결합니다 tail.

설치

sponge데비안 같은 시스템에 설치하려면 :

apt-get install moreutils

spongeRHEL / CentOS 시스템에 설치하려면 EPEL 저장소를 추가 한 후 다음을 수행하십시오.

yum install moreutils

선적 서류 비치

보낸 사람 man sponge:

sponge표준 입력을 읽고 지정된 파일에 씁니다. 쉘 재 지정과 달리 sponge출력 파일을 작성하기 전에 모든 입력을 흡수합니다. 이를 통해 동일한 파일에서 읽고 쓰는 파이프 라인을 구성 할 수 있습니다.


2
+1 감사 sponge합니다. 어려운 방법을 배운 모든 사람들에게 매우 유용합니다. sort importantfile.txt > importantfile.txt:)
dr01

4

확실히 "꼬리 + mv"가 훨씬 좋습니다! 하지만 sed의 경우 시도해 볼 수 있습니다

sed -i -e :a -e '$q;N;101,$D;ba' log

3

기록을 위해, ed당신과 같은 것을 할 수 있습니다

ed -s infile <<\IN
0r !tail -n 1000 infile
+1,$d
,p
q
IN

이 열립니다 infiler의 출력 EADS tail -n 1000 infile(즉, 그것은 1 라인 전에 출력을 삽입) 후 처음 파일의 마지막에 1 라인 무엇으로부터 삭제합니다. 교체 ,pw현재 위치에서 파일을 편집 할 수 있습니다.
그하지만 명심 ed솔루션은 대용량 파일에 적합하지 않습니다.


0

스크립트에서 수행 할 수있는 작업은 로그 회전 논리를 구현하는 것입니다. 함수를 통해 모든 로깅을 수행하십시오.

log()
{
   ...
}

이 함수는 먼저 다음과 같은 작업을 수행합니다.

printf "%s\n" "$*" >> logfile

그런 다음 파일 크기를 확인하거나 파일 회전이 필요한지 결정합니다. 그 시점에서, 파일이 logfile.1존재하는 경우, 파일을 제거 logfile.0존재하는 경우,로 이름이 변경되고, logfile.1그리고 logfile이름이 바뀝니다 logfile.0.

회전 여부는 스크립트 자체에 유지되는 카운터를 기준으로 결정할 수 있습니다. 1000에 도달하면 0으로 재설정됩니다.

항상 1000 줄로 엄격하게 다듬어야하는 경우 스크립트는 로그 파일이 시작될 때 줄 수를 계산하고 그에 따라 카운터를 초기화 할 수 있습니다 (또는 이미 1000 개를 초과하거나 초과하는 경우 회전을 즉시 수행).

또는 wc -c logfile특정 크기를 초과하여 회전 및 회전과 같은 크기를 얻을 수 있습니다 . 이런 식으로 파일을 스캔 할 필요가 없습니다.


0

내가 대신 사용했다 mvcp명령을 사용하면 소프트웨어가 실행되는 경우 적절한 장소에 일부 로그 파일을 가질 수 있음을 달성하기 위해. 다른 사용자 홈 디렉토리 또는 앱 디렉토리에 있고 하드 링크로 한곳에 모든 로그가있을 수 있습니다. mv명령 을 사용하면 하드 링크가 끊어집니다. 당신이 사용하는 경우 cp명령을 대신이 하드 링크를 유지합니다.

내 코드는 다음과 같습니다

TMP_FILE="$(mktemp "${TMPFILENAME}.XXX")"

for FILE in "${LOGFILE_DIR}"/* ; do
    tail -n $MAXLINES "${FILE}" > "${TMP_FILE}"
    if [ $(ls -g "${TMP_FILE}" | awk '{print $4}') -lt $(ls -g "${FILE}" | awk '{print $4}') ] ; then
        cp "${TMP_FILE}" "${FILE}"
    fi
done   

따라서 파일이 동일한 파일 시스템에 있으면 사용자에게 다른 권한을 부여하고 사용자 ${LOGFILE_DIR}처럼 길이를 수정할 수 있습니다.

이것이 mv명령이라면 파일 사이의 하드 링크를 잃어 두 번째 파일이 첫 번째 파일에 더 이상 연결되지 않습니다.

다른 곳에서 누군가 파일을 지우는 것을 허용하지 않으면 로그는 함께 있고 자신의 스크립트를 통해 잘 제어됩니다.

logrotate아마도 더 좋을 것입니다. 그러나이 솔루션에 만족합니다.

""에 의해 방해받지 않지만 내 경우에는 공백과 다른 특수 문자가 포함 된 파일이 있으며 ""주위에 또는 "}를 사용하지 않으면 전체가 잘 작동하지 않습니다.

예를 들어 오래된 파일이로 압축 자동화됩니다 일세 존재 OLDFILE.zip하고 압축 얻는 모든뿐만 아니라 파일에 나와있는 .zip_log(가) 때문에 .zip_log도이 디렉터리에 만에 LOGFILE_DIR내가 함께있어는 :

ln .zip_log "${LOGFILE_DIR}/USER_ZIP_log"

하드 링크이므로 동일한 파일

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