매일 같은 파일에 기록이 추가되는 로그 파일이 있는데 특정 날짜에 얼마나 많은 기록이 추가되었는지 확실하지 않습니다. 파일에 추가된 마지막 레코드를 인쇄해야 합니다.
cat file.txt, (yesterday file)
Shyam
Raghu
cat file.txt, (today file)
Shyam
Raghu
Ravi
Ravi가 파일에서 가장 최근에 업데이트된 레코드임을 알 수 있으므로 Ravi만 인쇄하면 됩니다.
명령을 사용해 보았 tail -f
으나 업데이트된 기록이 동적이기 때문에 전날의 기록도 가져옵니다. 오늘의 업데이트된 기록만 제공하는 스크립트나 명령이 있습니까?
답변1
이 41라인 TXR Lisp 프로그램을 데몬으로 사용하여 로그 파일을 모니터링하고 실시간으로 타임스탬프 버전을 생성할 수 있습니다.
TXR은 종속성이 매우 낮고 메모리 공간도 작지만 기능이 많습니다.
먼저 데모입니다.
foo
우리는 bar
하나이고 존재하지 않는 상태에서 시작합니다. foo
태그가 지정된 로그 파일은 없습니다. bar
태그가 포함된 로그 파일이 됩니다.
$ rm -f foo bar
우리는 stamp.tl
백그라운드에서 프로그램을 실행합니다. 나는 (해시 폭발) 줄을 추가하지 않았 #!
으므로(독자를 위한 연습) txr
이를 사용하겠습니다. 즉 -d
, 데몬으로 백그라운드에 배치됩니다.
$ txr stamp.tl -d foo bar
좋아요, 콘텐츠 제작을 시작해 보겠습니다 foo
.
$ echo "first post" >> foo
$ cat foo
first post
무슨 일이에요 bar
?
$ cat bar
2021-08-20 06:40:06 first post
로그 줄이 타임스탬프와 함께 표시됩니다. 계속하세요:
$ echo "second post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
$ echo "third post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post
이제 한번 시도해 보겠습니다. 로깅 소프트웨어가 foo
로그를 순환한다고 가정합니다. foo
사라진 다음 길이가 0인 상태로 다시 시작합니다.
$ rm foo
$ echo "rotated" >> foo
$ cat foo
rotated
무슨 일이야 bar
?
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post
2021-08-20 06:40:49 rotated
rotated
보시다시피 라인을 아주 잘 잡아줍니다.
물론 실제 해결책은 타임스탬프 없이 로깅할 수 있도록 원래 소프트웨어를 수정하는 것이지만, 그 동안은 임시방편에 불과할 수도 있습니다.
코드는 아래와 같이 표시됩니다. 이 프로그램에는 세 가지 옵션이 있습니다. 위에서 사용한 것 외에도 -d
대상 파일을 덮어쓰는 옵션(기본 동작은 추가하는 것)과 전체 버퍼링을 사용하여 쓰는 옵션(기본값은 라인 버퍼링을 사용하는 것)도 있습니다.
이 프로그램은 파일을 열고 계속 열어두기 때문에 출력 로그 회전을 지원하지 않습니다. 외부 로그 회전을 지원하려면 프로그램은 쓰기마다 파일을 열고 닫아야 합니다. 그렇지 않으면 내부 회전을 구현하십시오. 줄이 너무 많으면 파일을 닫고 회전으로 이름을 바꾼 다음 다시 엽니다.
;; Copyright 2021
;; Kaz Kylheku <[email protected]>
;; Vancouver, Canada
;; All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;; 1. Redistributions of source code must retain the above copyright notice,
;; this list of conditions and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above copyright notice,
;; this list of conditions and the following disclaimer in the documentation
;; and/or other materials provided with the distribution.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.
(defun stamp (infile outfile opts)
(when (and opts.daemonize
(not (daemon t nil))) ;; don't chdir
(put-line "failed to daemonize")
(exit nil))
(let* ((line-buf (if opts.fully-buffered "" "l"))
(write-mode (if opts.overwrite `w@{line-buf}` `a@{line-buf}`)))
(with-resources ((out (open-file outfile write-mode) (close-stream out))
(in (open-tail infile) (close-stream in)))
(whilet ((line (get-line in)))
(let ((stamp (time-string-local (time) "%Y-%m-%d %H:%M:%S")))
(put-line `@stamp @line` out))))))
(define-option-struct prog-opts nil
(w overwrite :bool
"Overwrite the output file instead of appending.")
(d daemonize :bool
"Run in the background as a daemon")
(f fully-buffered :bool
"Writes to the output file are flushed whenever\ \
an I/O buffer fills up. The default behavior is to\ \
flush after every line.")
(nil help :bool
"List this help text."))
(defvarl prog-name *load-path*)
(defun usage ()
(put-line "\nUsage:\n")
(put-line ` @{prog-name} [ options ] <infile> [ <outfile> ]`))
(let ((o (new prog-opts)))
o.(getopts *args*)
(when o.help
(usage)
o.(opthelp)
(exit nil))
(match-case o.out-args
((@infile @outfile) (stamp infile outfile o))
((@infile) (stamp infile `@infile.stamped` o))
(@else (usage) (exit nil))))