文字列が特殊文字列(カンマまたは区切り文字ではない)で区切られたファイルがあります<vvv>
。たとえば、最初のフィールドのすべての文字列が一意であることを確認したいとします。同じフィールドに重複行が見つかった場合は、重複行をすべて削除したい(最初の項目を保持)。
例:
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
aaa<vvv>new<vvv>new2
111<vvv>222<vvv>333
私は欲しい:
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
111<vvv>222<vvv>333
すでに現れたaaa<vvv>new<vvv>new2
ので削除しました。aaa
awk
私はそれが唯一の解決策ではない場合、私たちは好きではありません。 Linuxに慣れていない私にとっては、構文は少し複雑です。
答え1
使用しないでくださいawk
非常に:
$ awk -v OFS="<" '{ print NR, $0 }' file | sort -t '<' -u -k2,2 | sort -t '<' -k1,1n | cut -d '<' -f 2-
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
111<vvv>222<vvv>333
これは、元のデータにawk
行番号を挿入するためにのみ使用されます。<
これにより、元の行の順序を追跡できます。<
行番号と行の残りの部分の区切り記号として使用する理由は、元の最初のフィールドと行の残りの部分の区切り文字としても表示されるためです。
パイプラインの最初のステップを使用してawk
行番号を挿入した後、データは次のようになります。
1<aaa<vvv>bbb<vvv>ccc
2<xxx<vvv>yyy<vvv>zzz
3<aaa<vvv>new<vvv>new2
4<111<vvv>222<vvv>333
パイプラインの次のステップでは、それを2番目のフィールド(最初のソースフィールド)で並べ替えて重複エントリを削除します。結果は次のとおりです。
4<111<vvv>222<vvv>333
1<aaa<vvv>bbb<vvv>ccc
2<xxx<vvv>yyy<vvv>zzz
2つ目は、sort
最初のフィールドの行を数字でソートして元の行の順序を復元します。
1<aaa<vvv>bbb<vvv>ccc
2<xxx<vvv>yyy<vvv>zzz
4<111<vvv>222<vvv>333
次に、cut
最初のフィールド(および挿入された区切り文字)から数字を削除します。
を使用せずにソートされた出力を提供するソリューションawk
は次のとおりです。
$ sort -t '<' -u -k1,1 file
111<vvv>222<vvv>333
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
これは本質的に上記のパイプラインの2番目のステップであり、重複エントリを削除しながら最初のフィールドのファイルをソートします。
解決策awk
は次のとおりです。
$ awk -F '<' '!seen[$1]++' file
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
111<vvv>222<vvv>333
これは、最初のフィールドを名前付き連想配列のキーとして保存seen
し、その後に関連する値を増やします。与えられたキーの配列の値が0の場合(つまり、最初のフィールドが以前に見たことがない場合)、その行を印刷します。
答え2
または、均等に両方をawk
使用せずにcut
以下を使用してくださいsed
。
$ sed '=' file \
| sed 'N;s/\n/</' \
| sort -t"<" -u -k2,2 \
| sort -t"<" -k1,1 \
| sed 's/^[0-9]*<//'
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
111<vvv>222<vvv>333
しかし、これは非常に重い。 @Kusalanandaの最後の(awkベースの)ソリューションは次のとおりです。たくさんより良いもの。
教育目的でのみ上記sed
の最初の2つのブロックは、Kusalalanandaのより簡潔なawk
cmdと同じです。
sed '=' file
、今後の注文のために行番号を印刷してください。sed 'N;s/\n/</'
、パターンスペースに次の入力行を追加し(たとえば、「現在の行と次の行を結ぶ」)、行の終わりをに\n
置き換えます<
。
3番目と最後のsed
情報sed 's/^[0-9]*<//'
は、以前に各行の先頭に配置された行番号と "<"を何も置き換えません。
詳しくはコンソールに質問を投稿しsed
てください。$ info sed
答え3
GNU sedを使用すると、特定のタスクを実行できます。
$ sed -Ene '
G
/^([^<]+)<vvv>.*\n\1(\n|$)/d
P;s/<vvv>.*//;H
' input.txt
最初のフィールドを予約済みスペースに保存し、それを現在行の最初のフィールドと比較します。異なる場合にのみ保留を更新し、現在の行を印刷します。
答え4
次の2つの方法を試しました。
Method1
awk -F "<" '{if (!seen[$1]++)print }' filename
Method2
awk -F "<" '!a[$1]++' filename
出力
aaa<vvv>bbb<vvv>ccc
xxx<vvv>yyy<vvv>zzz
111<vvv>222<vvv>333