4

重複した行だけを印刷したくない、またはそれらを削除したくないと言うことから始めましょう。

パターン ファイルで grep を使用して、大きなデータ ファイルを解析しようとしています。

たとえば、パターン ファイルは次のようになります。

1243
1234
1234
1234
1354
1356
1356
1677

など、より多くの単一および重複エントリがあります。

入力データ ファイルは次のようになります。

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
ttttt   1555    bbbbbb
ppppp   1354    pppppp
yyyyy   3333    zzzzzz
qqqqq   1677    eeeeee
iiiii   4444    iiiiii

など 27000 行。

私が使うとき

grep -f 'Patternfile.txt' 'Inputfile.txt' > 'Outputfile.txt'

次のような出力ファイルが得られます。

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
ppppp   1354    pppppp

重複も報告するようにするにはどうすればよいので、最終的には次のようになりますか?:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
ppppp   1354    pppppp


qqqqq   1677    zzzzzz

さらに、パターン ファイル内のクエリが入力ファイル内の部分文字列と一致しない場合は、空白行を出力したいと思います。

ありがとうございました!

4

2 に答える 2

2

1つの解決策、ではなくgrepperl

元の投稿のデータを使用patternfile.txtして。inputfile.txt次のコンテンツはscript.plその仕事をする必要があります(一致する文字列は2番目の列であると想定します。そうでない場合は、regexp代わりに使用するように変更する必要があります。この方法の方が高速です)。

use warnings;
use strict;

## Check arguments.
die qq[Usage: perl $0 <pattern-file> <input-file>\n] unless @ARGV == 2;

## Open input files.
open my $pattern_fh, qq[<], shift @ARGV or die qq[Cannot open pattern file\n];
open my $input_fh, qq[<], shift @ARGV or die qq[Cannot open input file\n];

## Hash to save patterns.
my (%pattern, %input);

## Read each pattern and save how many times appear in the file.
while ( <$pattern_fh> ) { 
    chomp;
    if ( exists $pattern{ $_ } ) { 
        $pattern{ $_ }->[1]++;
    }   
    else {
        $pattern{ $_ } = [ $., 1 ];
    }   
}

## Read file with data and save them in another hash.
while ( <$input_fh> ) { 
    chomp;
    my @f = split;
    $input{ $f[1] } = $_; 
}

## For each pattern, search it in the data file. If it appears, print line those
## many times saved previously, otherwise print a blank line.
for my $p ( sort { $pattern{ $a }->[0] <=> $pattern{ $b }->[0] } keys %pattern ) { 
    if ( $input{ $p } ) { 
        printf qq[%s\n], $input{ $p } for ( 1 .. $pattern{ $p }->[1] );
    }   
    else {
         # Old behaviour.
         # printf qq[\n];

         # New requirement.
         printf qq[\n] for ( 1 .. $pattern{ $p }->[1] );
    }   
}

次のように実行します。

perl script.pl patternfile.txt inputfile.txt

そして次の出力を与えます:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
ppppp   1354    pppppp


qqqqq   1677    eeeeee
于 2012-03-26T20:09:59.550 に答える
1

grep入力のデータをパターンのデータに左結合しているので、パターンにはあまり関心がありません。

joinこれは、あなたと同様の問題を解決しようとして以来、よく知っている便利な Unix ユーティリティで(ほとんど) 実現できます。

ただし、いくつかの小さな違いがあります。

最初のコマンド:

join -a 1 -2 2 <(sort Patternfile.txt) <(sort -k2,3 Inputfile.txt)

そして説明:

  • -a 1ファイル 1 ( Patternfile.txt ) から結合できない行も含めることを意味します。これを追加したのは、一致しない行に「空白」行を含めたかったためで、これが最も近いものでした。
  • -2 2は、ファイル 2 のフィールド 2 で結合することを意味します (フィールドは と の両方に設定でき-1 FIELDます-2 FIELD。デフォルトはフィールド 1 です)。これは、Inputfile.txtで結合しているキーが2 列目にあるためです。
  • <(sort Patternfile.txt)— 結合が正しく機能するには、結合フィールドでファイルをソートする必要があります。
  • <(sort -k2,2 Inputfile.txt)— 入力ファイルをキー 2 からキー 2 まで (両端を含む) ソートします

出力:

1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1243 aatta qqqqqq
1354 ppppp pppppp
1356
1356
1677 qqqqq eeeeee

違い

指定した出力とこの結果のわずかな違い:

  • キー順でソートされています。
  • 結合できない行には、元のキーがまだ含まれています。それが問題である場合は、単純なパイプを介して一致しない行をクリアできますawk

    ... | awk '{ if ($2 != "") print; else print ""  }'
    
于 2013-09-24T20:56:31.990 に答える