行を削除したり、ファイルの順序を変更せずにn回以上発生した単語をすべて削除します。

行を削除したり、ファイルの順序を変更せずにn回以上発生した単語をすべて削除します。

複数のセクションで構成されるテキストファイルがあり、各セクションには2つのヘッダー行とスペースで区切られた単語で構成される本文行があります。例は次のとおりです。

Shares for DED-SHD-ED-1:
    [--- Listable Shares ---]
        backup      backup2
Shares for DED-SHD-ED-2:
    [--- Listable Shares ---]
        ConsoleSetup        REMINST     SCCMContentLib$     SCCMContentLibC$        SEFPKGC$        SEFPKGD$        SEFPKGE$        SEFSIG$     Source      UpdateServicesPackages      WsusContent     backup      backup2
Shares for DED-SHD-BE-03:
    [--- Listable Shares ---]
        backup      backup2     print$

削除したいボディラインで見るとすべての単語が発生3回以上

  • 削除したいみんな「最初の2回以降のすべての発生」と同様に発生。
  • 一致させるトークンは、スペースで区切られた「単語」です。つまり、print$英数字部分だけでなく全体ですprint
  • 一致は「完全な単語」にのみ適用する必要があります。つまり、部分文字列の一致は適用されません。たとえば、すべての発生はbackup削除にのみ含まれ、backup削除には含まれませんbackup2
  • ヘッダー行(Shares for ...および)は考慮されません。[--- Listable Shares ---]

上記の入力に必要な出力は次のとおりです。

Shares for DED-SHD-ED-1:
    [--- Listable Shares ---]
                
Shares for DED-SHD-ED-2:
    [--- Listable Shares ---]
        ConsoleSetup        REMINST     SCCMContentLib$     SCCMContentLibC$        SEFPKGC$        SEFPKGD$        SEFPKGE$        SEFSIG$     Source      UpdateServicesPackages      WsusContent
Shares for DED-SHD-BE-03:
    [--- Listable Shares ---]
                        print$

ご覧のように、3つの部分の本文行にbackupandという単語だけがbackup2表示されるため、削除されました。ただし、ヘッダー行は編集対象とは見なされないため、セクションヘッダー行の、およびSharesfor変更されていません。Listable

いくつかの注意:

  • これらのファイルのサイズは100kBから1MBまでです。
  • 同様の解決策が見つかりawk '++A[$0] < 3'ましたが、最初の2つの項目を維持し、行全体を見てみましょう。
  • 私は特にAwkベースのソリューションを探しているのではなく、何でも(Perlを除く;)することができます。

ベストアンサー1

最大1MBのファイルを処理する必要があるため、効率を向上させるには複数の配列の反転が必要です。単語を削除しているので、正確な間隔を維持することは重要ではないと思うので、代替行の各単語の前にTABが続きます。

これは、独自の awk プログラムを含む単一のシェル関数を含む Bash スクリプトです。入力ファイル引数を使用してstdoutに出力します。

結果をどのように確認したいのか分かりません。私は開発中に多くのデバッグをしました。たとえば、削除された単語とその頻度をstderrに書き込むのは簡単です。

#! /bin/bash

delByFreq () {

    local Awk='
BEGIN { SEP = "|"; Freq = 3; }
#.. Store every input line.
{ Line[NR] = $0; }
#.. Do not look for words on header lines.
/^Shares for / { next; }
/--- Listable Shares ---/ { next; }

#.. Keep an index to row/column of every unique word.
#.. So like: Ref ["backup2"] = "|2|3|5|1|5|7";
function Refer (row, txt, Local, f) {
    for (f = 1; f <= NF; ++f)
        Ref[$(f)] = Ref[$(f)] SEP row SEP f;
}
{ Refer( NR, $0); }

#.. Rearrange field indexes by line.
#.. So like: Del[row] = "|3|7|11"; for field numbers.
function refByLine (Local, word, j, n, V) {
    for (word in Ref) {
        n = split (Ref[word], V, SEP);
        if (n <= 2 * Freq) continue;
        for (j = 2; j < n; j += 2)
            Del[V[j]] = Del[V[j]] SEP (V[j+1]);
    }
}
#.. For every line with deletions, cross off the frequent words.
function Deletions (Local, row, j, f, n, V, X) {
    for (row in Del) {
        split (Del[row], V, SEP);
        split ("", X, FS); for (j = 2; j in V; ++j) X[V[j]];
        #.. Rebuild the line in field order. 
        split (Line[row], V, FS); Line[row] = "";
        for (j = 1; j in V; ++j)
            if (! (j in X)) Line[row] = Line[row] "\t" V[j];
    }
}
function Output (Local, r) {
    for (r = 1; r in Line; ++r) printf ("%s\n", Line[r]);
}
END { refByLine( ); Deletions( ); Output( ); }
'
    awk -f <( printf '%s' "${Awk}" ) "${1}"
}

    delByFreq "${1}"

おすすめ記事