このヘッダーの名前を指定する方法はわかりませんが、私が得たものは次のとおりです。
次のテキストを含むファイル:
[10:03:43] 10:03:35 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:03:44] CW2B1 T CW2B4 T CW2B5 T CW2B7 T
[10:03:44] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:03:44] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:03:44] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:03:44] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:03:44] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
[10:04:16] 10:04:28 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:04:36] CW2B1 F CW2B3 F CW2B5 F CW2B7 F
[10:04:36] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:04:36] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:04:37] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:04:37] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:04:37] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
その後、実際のファイルはTrueとFalseの値の変更で埋められます。
aにTrue項目があり、最後の項目以降に変更されていない場合は、その項目を削除し、値がFalseに(またはFalseからTrueに)変更されたときにのみ保持したいと思います。
アイデアは、文字列(CW1B1など)の最初の項目を見つけて、それに続くTまたはF値を変数として保存する必要があることです。次に、次に表示される項目を確認してT / F値を比較します。同じ場合は、切り取りまたは送信を使用して項目を削除し、次の項目を見つけます。値が変更された場合は無視して続行してください。
予想出力:
[10:03:43] 10:03:35 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:03:44] CW2B1 T CW2B4 T CW2B5 T CW2B7 T
[10:03:44] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:03:44] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:03:44] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:03:44] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:03:44] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
[10:04:16] 10:04:28 22JUN22 ConUP
[10:04:36] CW2B1 F CW2B3 F CW2B5 F CW2B7 F
[10:04:36]
[10:04:36]
[10:04:37]
[10:04:37]
[10:04:37]
おそらくより良い方法があるかもしれませんが、それでもフレームワークの助けが必要で、スクリプトに必要なすべての可能な変数を生成できます。
答え1
これはおそらくあなたが望むものです(テスト可能なサンプル入力/出力が提供されていないのでテストされていません)。
awk '
{
for ( i=2; i<=NF; i++ ) {
if ( $i ~ /^[TF]$/ ) {
tag = $(i-1)
val = $i
if ( map[tag] == val ) {
$(i-1) = $i = ""
}
map[tag] = val
i++
}
}
$0 = $0
$1 = $1
print
}
' file
答え2
使用幸せ(以前のPerl_6)
raku -e 'my @a = words; @a.splice(1, *-128); @a.splice(64,*-62); \
@a.=rotor(9); @a = @a>>.[1..*-1].flat.rotor(2); my @b; for 0..27 -> $i { \
@a[$i] eq @a[$i+28] ?? @b.push(@a[$i]~"+") !! @b.push(@a[$i+28]~"x") }; \
.say for @b.rotor(4)>>.join("\t|\t");'
出力:
CW1B1 T+ | CW1B3 T+ | CW1B5 T+ | CW1B7 T+
CW2B1 Fx | CW2B3 Fx | CW2B5 Fx | CW2B7 Fx
CW3B1 T+ | CW3B4 T+ | CW3B5 T+ | CW4B4 T+
CW4B8 T+ | CW5B4 T+ | CW5B8 T+ | CW6B4 T+
CW6B8 T+ | CW7B8 T+ | CW8B4 T+ | CW8B8 T+
CW9B4 T+ | CW9B8 T+ | CW10B4 T+ | CW10B8 T+
CW11B4 T+ | CW11B8 T+ | CW12B4 T+ | CW12B8 T+
Rakuを使うアイデアは次のとおりです。デフォルトでは、コードはtail
ログファイルで実行できるダッシュボードを構築します。入力を受け取り、分解して配列words
に割り当てます。@a
行1と8からsplice
追加3つを削除するために使用されますwords
。いくつかの並べ替えでは、1)を使用して9つの要素で構成された行を再生成し、rotor(9)
2)最初の列を削除して残りの8つの列を2つの要素で構成される行にペアにすることができます(例:)("CW1B1", "T"), ("CW1B3", "T"), ("CW1B5", "T")...
。
この時点から、番号付きの28の要素があることがわかります0..27
。 28要素の反復を使用して、および間eq
の文字列同一性を取得します。 「Test True False」のRakuの三項演算子は、Trueの場合、最初の文字列を配列にプッシュし(両方の値が変更されていないという意味を追加します)、Falseの場合は2番目の文字をプッシュします。文字列が配列にプッシュされます(値が変更されたことを示すためにaが追加されます)。@a[$i]
@a[$i+28]
??
!!
@b
+
@b
x
rotor(4)
入力例:
[10:03:43] 10:03:35 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:03:44] CW2B1 T CW2B4 T CW2B5 T CW2B7 T
[10:03:44] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:03:44] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:03:44] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:03:44] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:03:44] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
[10:04:16] 10:04:28 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:04:36] CW2B1 F CW2B3 F CW2B5 F CW2B7 F
[10:04:36] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:04:36] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:04:37] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:04:37] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:04:37] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
https://stackoverflow.com/questions/3416467/how-to-tail-f-the-latest-log-file-with-a-given-pattern
https://docs.raku.org/routine/splice
https://docs.raku.org/言語/operators#index-entry-operator_ternary
https://raku.org
答え3
次のPerlスクリプトは、各入力行から重複した変数値を削除します。以前に見たことがないか、最後に見た後に変更された変数のみが出力に含まれます。空の行(つまり、新しい変数や変更された変数のない行)は印刷されません。
$ cat remove-dupes.pl
#!/usr/bin/perl
use strict;
# %vars is a hash (associative array) to store last-seen T/F values
# for the "variables". This is global in scope, i.e. defined here
# outside of the main loop because its keys & values need to be
# remembered across lines.
my %vars;
# read in and process each input line
while(<>) {
chomp; # remove newline character at end of line
# @out is an array to hold "VAR [TF]" values that we either
# haven't seen before or have changed since last time we saw
# them. i.e. the values we want to output. It needs to be
# reset to empty every time we read a line.
my @out = ();
# extract the first word (i.e. "ConUp") from input line
# by deleting all "VAR [TF]" strings from the line
my $first_word = $_;
$first_word =~ s/ ?\w+\s+[TF]//g;
# add it to @out if it isn't empty
push @out, $first_word if $first_word;
# Iterate over each "VAR [TF]" string in the line. Split
# it into the key (variable name) and value (T or F).
# If it's new or changed then add it to @out and
# remember its current value in %vars
while (/ ?\b(\w+ [TF])\b/g) {
my ($key,$val) = split / /, $1;
next if ($vars{$key} eq $val);
push @out, $1;
$vars{$key} = $val;
};
# join (with spaces) and print @out if it isn't empty.
if (@out) {print join(" ",@out), "\n"};
}
注:行に "VAR [TF]"以外の文字列がある場合、出力はその行の先頭に移動します。これはバグと見なされる可能性があります。サンプルデータの唯一のインスタンスは、最初の行の先頭にある「ConUp」なので、必要に応じて機能します。変数を呼び出すべきではありませんが、$first_word
この方法は良い方法です。$anything_that_doesnt_match_a_boolean_variable_pattern
入力ファイルには削除する必要がある重複変数値が含まれていないため、その値を含むファイルを作成しました(そして変更される変数インスタンスのいくつかを追加しました)。
$ cat file2.txt
ConUp CW1B1 T CW1B2 T CW1B3 F CW1B4 F
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 F CW2B4 T
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 T CW2B4 T
出力例:
$ ./remove-dupes.pl file2.txt
ConUp CW1B1 T CW1B2 T CW1B3 F CW1B4 F
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F
CW2B1 T
CW2B1 F CW2B3 T
更新されたバージョン:
このバージョンでは、各行の最初の34文字を「最初の単語」として抽出します。これはsprintf()
、各要素を@out
10文字の幅の文字列にフォーマットするために使用され、出力から末尾のスペースを削除します。\s*
また、\s+
単一のスペースの代わりに合計を使用してスペース文字を一致または分割します。元のスクリプトの説明がまだ適用されているので(マイナーな変更を含む)、簡潔にするために説明を削除しました。
$ cat remove-dupes2.pl
#!/usr/bin/perl
use strict;
my %vars;
while(<>) {
chomp;
my @out = ();
my $first_word;
($first_word = $_) =~ s/\b\w+\s+[TF]//g;
$first_word =~ s/^(.{34})\s+$/$1 /;
push @out, $first_word if $first_word;
while (/\s*\b(\w+\s+[TF])\b/g) {
my ($key,$val) = split /\s+/, $1;
next if ($vars{$key} eq $val);
push @out, sprintf("%-10s",$1);
$vars{$key} = $val;
};
my $out = join(" ",@out);
$out =~ s/\s+$//; # remove trailing spaces
print "$out\n";
}
新しい入力データを使用した出力例(input.txt
)。まだではない正確に例の出力と同じですが、まだわずかな空白の違いがありますが、出力は上記の元のスクリプト出力よりはるかに近いです。
$ ./remove-dupes2.pl input.txt
[10:03:43] 10:03:35 22JUN22 ConUP CW1B1 T CW1B3 T CW1B5 T CW1B7 T
[10:03:44] CW2B1 T CW2B4 T CW2B5 T CW2B7 T
[10:03:44] CW3B1 T CW3B4 T CW3B5 T CW4B4 T
[10:03:44] CW4B8 T CW5B4 T CW5B8 T CW6B4 T
[10:03:44] CW6B8 T CW7B8 T CW8B4 T CW8B8 T
[10:03:44] CW9B4 T CW9B8 T CW10B4 T CW10B8 T
[10:03:44] CW11B4 T CW11B8 T CW12B4 T CW12B8 T
[10:04:16] 10:04:28 22JUN22 ConUP
[10:04:36] CW2B1 F CW2B3 F CW2B5 F CW2B7 F
[10:04:36]
[10:04:36]
[10:04:37]
[10:04:37]
[10:04:37]
[HH:MM::SS]
ところで、ほとんど空の行(含まれている行のみ)を印刷したくない場合は、print "$out\n";
行をprint "$out\n" unless ($out =~ /^\[[^]]\]\s*$/);
。
唯一の違いを確認するには、diff
空白(output.txt
例出力)です。
$ ./remove-dupes2.pl input.txt > out.txt
$ diff --ignore-space-change -u output.txt out.txt
$