他の行が現在の行で始まる場合は、行を削除する(列ベース)

他の行が現在の行で始まる場合は、行を削除する(列ベース)

次のようにinput.txtファイルがあります。商標区切り形式:

aaaa    bbbb
aaaa    bbbb    c
aaaa    bbbb    c   dd
aaaa    bbbb    cc
aaaa    bbbb    x
aaaa    bbbb    xx
dddd    eeee
dddd    eeee    f
dddd    eeee    f   g
dddd    eeee    fe
h   ii  j

各行について、他の行にすでに先行列が含まれていることを確認してください。その場合は、その行を削除してください。それ以外の場合は、この例を見てみましょう。

  • 最初の列が同じ追加列を含む別の行(2行)があるため、最初の行は削除されます。その場合は、最初の行を削除して2番目の行を維持してください。
  • 同じ最初の列を持つ追加の列を含む別の行(3行目)があるため、2行目は削除されます。この場合は、2行目を削除して3行目を維持してください。
  • 同じ最初の列を持つ他の行がないため、3番目の行は削除されません。この場合、3行目を保持します。

その他などの出力ファイルは次のようになります。

aaaa    bbbb    c   dd
aaaa    bbbb    cc
aaaa    bbbb    x
aaaa    bbbb    xx
dddd    eeee    f   g
dddd    eeee    fe
h   ii  j

何百万もの行をシームレスに実行できるソリューションを見つけることもできます。

答え1

これは入力を逆順に並べ替えるので、「foobar」が「foo」の前に来ます。これは、現在の行が各行の最初の文字で始まる前の行のサブストリングである場合には発生しません。現在を印刷します。ライン(foo)。

$ sort -r file | awk 'index(prev FS,$0 FS) != 1; {prev=$0}'
h   ii  j
dddd    eeee    fe
dddd    eeee    f   g
aaaa    bbbb    xx
aaaa    bbbb    x
aaaa    bbbb    cc
aaaa    bbbb    c   dd

出力順序が重要な場合は、この問題を解決する方法がいくつかあります。たとえば、次のようになります。

$ cat -n file | sort -k2r |
    awk '{orig=$0; $1=""} index(prev FS,$0 FS) != 1{print orig} {prev=$0}' |
    sort -n | cut -f2-
aaaa    bbbb    c   dd
aaaa    bbbb    cc
aaaa    bbbb    x
aaaa    bbbb    xx
dddd    eeee    f   g
dddd    eeee    fe
h   ii  j

答え2

文字以外の列(フィールド)に基づいて他の行のプレフィックス行を削除しようとしています。これはawk(1)を使用して達成できます。まず、長い行が最初に来るように、データを逆順にソートします。したがって、行がプレフィックスの場合、その行はプレフィックスになります。その後、awkを使用してフィールドをスキャンして、保存した最後の行と一致することを確認し、その場合は削除できます。

sort -r input.txt | awk '
    { for (i=1; i<=NF; i++) if (save[i] != $i) {keep=1; break} }
    keep == 0 { next }
    { delete save; for (i=1; i<=NF; i++) save[i]=$i; keep=0; print }
'

最初の awk 操作は、現在のフィールドを保存されたフィールドセットと比較します。フィールドのいずれかが異なる場合は、その行をキーパーとしてマークします。すべて同じであれば、私たちではないので、2番目のアクションが適用され、ゴールキーパーでなければラインをスキップします。 3番目のジョブは、現在の行を保存して印刷し、次の行を準備するために保留フラグをクリアします。

何百万行もの長さのデータセットがないので、これがうまくいくかどうかはわかりません。一度試して確認してみてください。

答え3

行の先頭に固定されたパターンで最も長く一意の一致を探しているので、ファイル名がtstであるとします。

while read l ; do if [ $(grep -c -E "^$l" tst) -eq 1 ]; then echo $l; fi ; done < tst

ただし、最も長いパターンが繰り返されると失敗するため、これを処理する必要があります。

while read l ; do if [ $(grep -c -E "^$l" <<<$(sort tst | uniq)) -eq 1 ]; then echo $l; fi ; done <<<$(sort tst | uniq)

関連情報