Linux コマンドを使用して列に基づいて一意の行のみを取得するにはどうすればよいでしょうか?

Linux コマンドを使用して列に基づいて一意の行のみを取得するにはどうすればよいでしょうか?

これが私のデータセットです:

col1,col2,col3
a,b,c
a,d,f
d,u,v
f,g,h
d,u,g
x,t,k

期待される出力:

f,g,h
x,t,k

選択基準:

何かが複数回発生した場合col1、関連する行はすべて削除されます。

sortLinuxまたはuniq他の何かを使用して解決できますか?

答え1

ここでは、「非バッファリング」(1) 2 パス アプローチを示しますawk(通常のファイルでのみ機能します)。

awk -F',' 'NR==FNR{cnt[$1]++;next} FNR>1&&cnt[$1]==1' input.csv input.csv 

これにより、ファイルは 2 回処理されるため、コマンドラインで引数として 2 回指定されます。

  • 引数は-F','フィールド区切り文字を設定します,
  • 最初のパスでは、グローバル行カウンタ がファイルごとの行カウンタNRに等しい場合、列 1 の各値が配列内で何回出現するかを登録します(配列は値を「配列インデックス」として受け取ります)。ただし、処理はすぐに次の行にスキップします。FNRcnt
  • 2 番目のパスでは、最初の列の現在の値の発生カウンタがちょうど 1 であり、ファイル内の行番号が 1 より大きいかどうか (ヘッダーをスキップするため) を確認します。これが true の場合のみ、現在の行が印刷されます。これは、awkルール ブロックの外側の式が現在の行を印刷するように指示する構文trueを使用しますawk

(1)私が投稿したコメントに対する反応として非バッファリング引用符で囲むのは、ソリューションがファイルの一部のデータを一時的にRAMに保存するため、するRAMの使用量が伴います。ただし、ファイルの内容をそのまま保存するわけではありません。加えてRAM内の他のスクロールキーピングデータ(実際の意味での「バッファリング」を検討します。

答え2

ファイルがあると仮定すると、/tmp/dataPerl ワンライナーで実行できます。

perl -e 'while(<STDIN>) { /(^\S+?),/; $show->{$1}=$_; $count->{$1}++;}; foreach(keys %$show) {print $show->{$_} if($count->{$_} == 1);}' < /tmp/data

またはもっと読みやすい...:

while(<STDIN>) { #loop through all lines in the input and put the lines in "$_"
  /(^\S+?),/; #Everything before the first "," now ends up in "$1"
  $show->{$1} = $_; #a hash will be created with as keys the "$1" and as values the "$_"
  $count->{$1}++; #In the hash $count the number of occurrences will be increased everytime the same $1 appears
}
foreach(keys %$show) { #loop trough all lines
  print $show->{$_} if($count->{$_} == 1); #only print them if they occur once
}

答え3

awk唯一の解決策

  1. 秩序を守らない

    awk -F, 'NR>1 { count[$1]++ ; line[$1]=$0 ;} 
       END { for ( c in count) if (count[c] ==1) print line[c]}' data
    
  2. 秩序を保つ

    awk -F, 'NR>1 { row[a]=$0; col[a]=$1; count[$1]++; ++a; } 
       END { for (i=0; i<a; ++i) if (count[col[i]]==1) print row[i]; }' data
    

どこ

  • -F,awkに,セパレータとして使用するように指示する

  • NR>1 最初の行の後

  • count[$1]++最初の列の要素を数える

  • line[$1]=$0 店舗ライン

  • ENDファイルの終わりの後

  • for ( c in count)要素をループする

  • if (count[c] ==1)たった一つでも

  • print line[c]印刷行

  • acol[]順序保存型で行の順序を保存するために使用されます。

これは1行にまとめることができますが、読みやすくするために折り返しています

答え4

必須の POSIX ツールの任意のバージョンと入力内の任意の文字を使用して、装飾/並べ替え/使用/装飾解除を行います (入力が実際にはコンマや改行を含むことができる引用符で囲まれたフィールドを持つ CSV である場合は除きますが、その場合は他のすべての回答も失敗します)。また、出力の入力行の順序を保持し、入力を一度だけ開くので、入力がパイプまたはファイルから来ている場合、入力全体をメモリに保存せずに機能します。

$ awk 'BEGIN{FS=OFS=","} NR>1{print ++cnt[$1], NR, $0}' file |
    sort -nt, -k1,1r -k2,2 |
    awk -F, '(!seen[$3]++) && ($1==1)' |
    cut -d, -f3-
f,g,h
x,t,k

関連情報