特定の列のすべてのファイルにパターンが一度だけ含まれている場合に行を削除する方法

特定の列のすべてのファイルにパターンが一度だけ含まれている場合に行を削除する方法

私のファイルには複数の列が含まれており、最初の列はIDに対応しています。ファイル全体でIDが一度だけ表示される場合(最初の列)、行を削除したいと思います。 IDが何度も表示される場合は、その行をファイルに保存したいと思います。 IDはAで始まる文字(時には数字)で構成されています(他のすべての文字/数字はランダムな順序です)。たとえば、A2SGWS7CUGU8GB

私が持っているなら:

# id             #column 2 ...
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
ADE8GST9URWPOS
ABXLMWJCQFGVXV
A2SGWS7CUGU8GB

ADE8GST9URWPOSと を含む行はABXLMWJCQFGVXV一度だけ表示されるので、削除したいと思います。どうすればいいですか?

答え1

まず、保持したいすべての冗長IDが返されます。

$ awk '{ print $1 }' <file | sort | uniq -d
A2SGWS7CUGU8GB

を使用して、最初のスペースで区切られたフィールド(ID)を抽出してこれを実行しますawk。その後、それらをソートしてuniq -d重複したIDのみを出力するために使用されます。

その後、これらの(この場合は単一の)IDを使用して元のファイルからその行を抽出できます。まず、次のようにソートする必要がありますjoin

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file )
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

シェルが<(...)一時ファイルを使用したプロセスの置き換えをサポートしていない場合は、一時ファイルを使用して2つのステップでこれを実行できます。

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

使用ただ awk、これは次のように行うことができます。

$ awk 'NR == FNR { count[$1]++; next } count[$1] > 1' file file
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

コードはファイルを2回読み取るため、コマンドラインでファイルを2回参照しますawk

最初は、連想配列がcount各IDの発生回数で満たされ、第2に、IDが複数回発生する各行が出力される。

上記の2つの方法の違いは、awk最後のコマンドが元のデータの順序を維持しますが、一意のIDの数に比例してメモリを消費することです。最初のアプローチはソートされた結果を生成するため、より適している可能性があります。とても大きいデータ。


ヘッダー行を保持するには、コマンドを少し変更する必要があります。

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file ) | cat <(head -1 file) -

または

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted > file.noheader
$ head -1 file | cat - file.noheader

または

$ awk 'NR == 1 ; NR == FNR { count[$1]++; next } count[$1] > 1' file file

答え2

awk '
  !B {a[$1]++}
  B && a[$1] > 1
' B=0 file B=1 file

最初のフィールド(= ID)を取得して並べ替え、IDを統合し、重複した項目のみを保持します。これをxargsに渡し、各IDに基づいてegrep ERE正規表現を作成します。

< file \
  cut -d" " -f1          \
| sort  | uniq -d        \
| xargs -I{} echo ^{}\\s \
| grep -Ef - file        \
;

perlslurpファイルオプションを使用し-0777てレコードを介して正規表現を実行すると、各行の先頭にさらに下^の最初のフィールド(= ID)が表示されるか、IDが以前に見つかった場合は現在の行が印刷されます。

perl -0777ne '
  () = m/(?msx)
      ^
      (?<line>
        (?<ID> A\w+)
        \h.*?\n
      )

      (?=
        (?:.*?\n)?
        (?<lukahead> \g{ID}|$)
      )

      (?{ my %seen;
        my($id_visible_ahead, $id_already_seen) =
          map { $_ > 0 } 
length($+{lukahead}), $seen{$+{ID}};

        print($+{line}),$seen{$+{ID}}++
          if $id_visible_ahead || $id_already_seen;
      })
   /g;
' file

出力:

A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

関連情報