awkを使用してこの5分を記録し、出力を別のファイルに変換するにはどうすればよいですか?

awkを使用してこの5分を記録し、出力を別のファイルに変換するにはどうすればよいですか?

次の内容を含むlistlogというログファイルがあります。

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
line 3
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid
line 3

t1とt2の間に記録されたログをフィルタリングして2つの連続したログ行を印刷したいと思います。私はawkとif条件とgrepを使って書いています。しかし、エラーが発生しました。

これが t1 < (16:09:17, 16:19:17) < t2 と仮定してフィルタリングして新しいファイルに書きたい内容です。

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

これは私が書いたawkスクリプトです。

t1=$(date -d "$min_change minutes ago" +"%F %T")
t2=$(date +"%F %T")
cat $listlog | awk -v t1="$t1" -v t2="$t2" -v listlog="$listlog" '{
        if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
        {
                if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
                {
                        grep -A 2 $0 $listlog >> /tmp/temp.txt
                }
        }
        }'

私が得るエラーは次のとおりです。

awk: cmd. line:2:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:2:                       ^ unterminated regexp
awk: cmd. line:3:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:3:                                                ^ unexpected newline or end of string
awk: cmd. line:4:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
awk: cmd. line:4:                                         ^ syntax error.
awk: cmd. line:5:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 ) 
awk: cmd. line:5:                                                   ^ unexpected newline or end of string
awk: cmd. line:6:                       grep -A 2 $0 $listlog >> /temp/temp.txt
awk: cmd. line:6:                                             ^ syntax error
awk: cmd. line:7:                       grep -A 2 $0 $listlog >> /temp/temp.txt.
awk: cmd. line:7:                                                                ^ unexpected newline or end of string

答え1

スクリプトの問題を説明し始めるのは難しいですが、以下は最も重要なことをまとめたものです。

  1. awkあなたが書いたのは台本ではありません。awkシェルスクリプトに含まれているスクリプトでもありません(通常は完璧です)。これは、いくつかのシェルコードとawkその中にシェルコードを含めようとする試みの奇妙なブレンドです(awkシェルコマンドを解釈または実行せずに)。

    とにかく、外部プロセスにフォークしないと、内部的にgrepこのように実行することはできません。そして正規表現のパターンマッチングが可能なので、awkこれを行う必要はありません。awk

  2. コードにインデントがないので、読みにくいです。

    アップデート:質問を編集してフォーマットを変更したところ、コードにインデントがあることがわかりました。ただし、<br/>Markdownエディタに組み込まれているテキスト書式設定機能を使用する代わりに、HTMLタグを使用して書式設定します。

  3. 1番と2番のエントリは、おそらく質問を投稿してから7時間以内に回答やコメントを受け取らなかった理由でしょう。すべての読者(少なくとも私の読者)の初期反応は「WTF?これは言えない。どこから始めるべきかさえ分からない…通過」です。

  4. シェルまたは日付awk比較を試して日付比較を実行することはできません。より大きいまたはより小さいなどの数値比較を実行するには、日付を数値に変換する必要があります(たとえば、time_t1970年1月1日の真夜中(UTC)である「epoch」以降の秒を表すunix形式)。

  5. で好きなようにできますが、日付変換機能が組み込まれていないawkため、必要以上に難しいでしょう。日付と時刻のライブラリ機能が良い場合は、はるかawkに簡単です。perlあなたが書くスクリプトはperlコードよりもコードスタイルに近いので、これはあなたにとって良いことですawk


これはPerlで欲しいものを達成する非常に簡単で直接的な方法です。コマンドライン引数が必要です(perlGetSelect::標準ライブラリモジュール)。 Getopt::StdPerlに含まれるコアPerlライブラリモジュール。

パラメータは順序に関係なく提供できます。すべてのオプションパラメータ(、、および)-m-n必須ではなく、-sコマンドラインに指定されていない場合はデフォルト値を持ちます。未処理の引数はGetopt::Std入力ファイル名として扱われます。スクリプトは標準入力と同様にすべての入力ファイル名を処理できるため、ログファイルをスクリプトにリンクできます。

スクリプトも日付::分析Perlのモジュール時間::日付日付文字列をepoch以降の秒コレクションに変換します。

Date::ParsePerlにはこれが含まれていないため、インストールする必要があります。 Debian(またはUbuntu、Mint、または他のDebian関連のディストリビューション)を使用している場合は、他のほとんどsudo apt-get install libtimedate-perlのディストリビューションでもパッケージを提供します。セントースパッケージはPerl-TimeDate-2.30-2Centos 7の場合、またはPerl-TimeDate-2.30-15セントース8の場合。それ以外の場合は使用できますcpan

#!/usr/bin/perl
use strict;
use Getopt::Std;
use Date::Parse;

my %opts;
getopt('m:s:n:', \%opts); # -m minutes, -s start time, -n number of lines

my $st  = $opts{s} || -1; # start time, default now.
my $min = $opts{m} ||  5; # number of minutes after $st to match, default 5.
my $nl  = $opts{n} ||  2; # No. of extra lines to print after match, default 2.

if ($st == -1) {
  $st = time();           # now
} else {
  $st = str2time($st);    # convert time string to seconds since epoch
};
my $et = $st + $min * 60; # calculate ending time

my $p = -1; # input lines are printed only when $p > -1

# main loop, read and process all input file(s).
while (<>) {
  if (m/^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)/) {
    my $t = str2time($1);
    $p = $nl if ($t >= $st && $t <= $et);
  };

  if ($p > -1) { print; $p-- };
};

たとえば、別の名前で保存してextract.pl実行可能にし、chmod +x extract.pl次のように実行します。

$ ./extract.pl -s "2021-08-12 16:09:00" -n 2 -m 5 listlog 
2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

>>/tmp/temp.txt必要に応じて、コマンドラインの最後に追加して出力をリダイレクトできます。

関連情報