3

以下に示すデータを含むファイルがあります。最初のコンマ区切りフィールドは何度でも繰り返すことができ、このフィールドの任意の値を6回繰り返した後の行のみを印刷したい

たとえば1111111、最初のフィールドとして8つのフィールドがあり、これらのレコードの7番目と8番目だけを印刷したい

入力ファイル:

1111111,aaaaaaaa,14
1111111,bbbbbbbb,14
1111111,cccccccc,14
1111111,dddddddd,14
1111111,eeeeeeee,14
1111111,ffffffff,14
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,aaaaaaaa,14
2222222,bbbbbbbb,14
2222222,cccccccc,14
2222222,dddddddd,14
2222222,eeeeeeee,14
2222222,ffffffff,14
2222222,gggggggg,14
3333333,aaaaaaaa,14
3333333,bbbbbbbb,14
3333333,cccccccc,14
3333333,dddddddd,14
3333333,eeeeeeee,14
3333333,ffffffff,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

出力:

1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

私が試したのは、1番目に対して2番目と3番目のフィールドをトランスポートして、またはnawkのフィールドで使用できるようにすることです。$7$8

#!/usr/bin/ksh awk -F"," '{ a[$1]; b[$1]=b[$1]","$2 c[$1]=c[$1]","$3} END{ for(i in a){ print i","b[i]","c[i]} } ' file > output.txt
4

5 に答える 5

7

レコードが順不同の場合

つまり、「1111111」項目が入力全体にランダムに分散されている可能性があります。

$ awk -F, '++a[$1] > 6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

これはどのように作動しますか?

ご存じのとおり、awk の-Fオプションは区切り文字を設定します。特殊文字でない場合は、引用する必要はありません。

awk スクリプトは、一連のcondition { action; }. 条件が欠落している場合、アクションはすべての行に適用されます。アクションが欠落している場合は、 であることが暗示されますprint;。したがって、単純な条件で構成される awk スクリプトは、その条件が true と評価されるすべての入力行を出力します。

この場合、条件にはアクションの要素もあります。つまり、キーが最初のフィールドである連想配列の要素をインクリメントします。条件が true と評価されるかどうかに関係なく、インクリメントが発生します。また、変数のに置くのではなく++ 前に置くと、インクリメントは評価のではなくに発生します。(私は と の違いについて話している。) そして、インクリメントされた結果の配列要素が 6 より大きい場合、条件は true と評価され、行が印刷されます。++varvar++

これは他の回答のソリューションと機能的に同等ですperlが、その性質上、 awk スクリプトはさらにタイトで (おそらく) シンプルです。そしてもちろん、それはより速い可能性があります。(私の非公式なテストでは、上記の awk スクリプトは別の回答の同等の perl スクリプトよりも 2 倍以上速く実行され、0.23 秒のユーザー時間で 250000 行の入力を処理しましたが、perl では 0.61 秒でした。)

あなたのレコードが注文された場合

つまり、すべての「1111111」行が一緒になっています。

$ awk -F, '$1!=f{c=0;f=$1} ++c>6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

これはどのように作動しますか?

  • 前回とは異なる $1 を使用している場合 (これは最初の行でも同様です)、カウンターをリセットし、将来の比較のために $1 を変数に保存します。
  • 次に、カウンターをインクリメントし、カウンターが 6 を超えた場合に (暗黙的に) 行を出力します。

これには、配列でメモリを消費しないという利点がありますが、入力全体にランダムに分散される可能性のある一致する行を処理するのではなく、一連の行のセットを共通の $1 と一致させることが目標である場合にのみ適切です。

于 2012-09-06T13:24:32.563 に答える
6
$ perl -F',' -ane 'print unless $seen{ $F[0] }++ < 6' file.txt

説明

  • -a自動分割モードを有効にし、分割トークンとして-F','指定し、結果リストを結果として格納します','@F
  • -n暗黙的な行ごとのループを有効にします
  • -e次の引数 ('...'この場合) を Perl コードとして実行します
  • %seen最初のフィールドが表示された回数を追跡します
于 2012-09-06T13:20:00.970 に答える
4

データ内のドットがコンマであると仮定すると、この Perl コマンドは要求したことを実行します

perl -aF, -ne 'print if ++$n{$F[0]} > 6' myfile

出力

1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
于 2012-09-06T13:13:01.413 に答える
1

awk (filter.awk) を使用:

BEGIN    { FS = "[,.]"          }   
o == $1  { cnt++                } 
o != $1  { o=$1; cnt = 0;       }
cnt >= 6 { print $0             }

使用するには:

awk -f filter.awk input_file
于 2012-09-06T12:45:15.980 に答える
0

特にawkソリューションが必要な場合は、以下を参照してください。

awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' file

以下でテスト済み:

> awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' temp
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

これにperlスクリプトが必要な場合は、以下を参照してください。

#!/usr/bin/perl

use strict;
use warnings;

my $count=0;
my $prev="";
open (MYFILE, 'temp');
while (<MYFILE>) {
       my @a=split(/,/);
       if($prev==$a[0])
       {
        $count++;
        if($count>6)
         {
           print "$_";       
          }
        }
        else
        {
        $prev=$a[0];
        $count=1; 
        }

 }
close (MYFILE);
于 2012-09-06T13:22:18.557 に答える