毎日同じファイルに履歴が追加されるログファイルがありますが、特定の日にどれだけの履歴が追加されたかわかりません。ファイルに追加された最後のレコードを印刷する必要があります。
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
消えてから長さがゼロの状態で再起動します。
$ 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
ご覧のとおり、ラインをとてもよくつかみます。
もちろん、実際の解決策はタイムスタンプなしでロギングできるように元のソフトウェアを変更することですが、その間は一時的な方法に過ぎません。
コードは以下のように表示されます。このプログラムには3つのオプションがあります。上記で使用したものに加えて、ターゲット-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))))