すべての行の2番目のフィールドに同じ最初のフィールドの値がある場合

すべての行の2番目のフィールドに同じ最初のフィールドの値がある場合

スペースで区切られた2つの列を持つファイルがあります。 2番目の列にはTorの1つだけがありますF。最初の列の文字を読みたいです。たとえば、A2 番目の列に同じ文字の 3 行がある場合は保持されますが、2 番目の列に混合文字がある場合は削除されます。TABD

A T
A T
A T
B T
B T
B F
C F
C F
D F
D T
D F

2番目のフィールドに同じ最初のフィールドのすべての行に値がある場合は、印刷したいと思います。予想出力:

A T
A T
A T
C F
C F

たぶんawkそれは可能ですか?助けてくれてありがとう!

答え1

1つの方法は次のとおりですawk

awk 'NR==FNR{if (x[$1]++){if ($2!=t){z[$1]++}} else {t=$2};
next}!($1 in z)' infile infile

このプロセスはファイルを2回処理します。最初のパスでは、最初のフィールドが同じ値の場合、2番目のフィールドの値が異なることを確認します。その$1場合は配列インデックスとして使用され、2番目のパスは次の場合にのみバッチを印刷します。最初のフィールドはそのフィールドのインデックスではありません。または、次のように
使用しても大丈夫なら:sortawk

sort -u infile | awk 'NR==FNR{seen[$1]++;next}seen[$1]==1' - infile

sort -uファイルから重複した行を削除し、結果をパイプしてawk最初のフィールドの発生回数を計算し、ファイル全体を再処理し、数があれば行を印刷します1

答え2

sed -e '
   # this is a do-while loop which collects lines till the time the first
   # field remains the same. We break out of the loop when we see
   # a line whose 1st field != prev lines 1st field **OR** we hit the eof.
  :a
     $bb
     N
  /^\(\S\+\) .\(\n\1 .\)*$/ba

  :b

  # all equal
  # **Action:** Print and quit

  /^\(\S\+ .\)\(\n\1\)*$/q


  # all same 1st fld, but lines unequal, otw would have matched above
  # **Action:** Drop the whole block as its uninteresting

  /^\(\S\+\) .\(\n\1 .\)*$/d


  # all equal, and trailing line part of next line
  # **Action:** Display upto the last newline and restart 
  # with the trailing portion

  /^\(\(\S\+ .\)\(\n\2\)*\)\n[^\n]*$/{
     h
     s//\1/p   
     g
  }


  # of same 1st fld but some lines unequal, and trailing portion has
  # next line
  # **Action:** strip till the last newline, and restart over with the
  # trailing part

  s/.*\(\n\)/\1/
  D
' yourfile

これは「Sed」が扱う非常に興味深い問題です。しかし、私が見つけたのは良いことです。それとも、OTがSEによって提供されるより大きな入力セットであるべきですか?私の提案は、実際のサイズと種類のテストケースをhttp://pastebinサイトに配置できることです。これはこの種の作業に非常に役立ちます。

答え3

アクセス権がある場合GNUデータの混合、次のようにデータを縮小できます。

datamash -W groupby 1 countunique 2 collapse 2 < file 
A   1   T,T,T
B   2   T,T,F
C   1   F,F
D   2   F,T,F

awkこれにより、次のような後処理が容易になります。

datamash -W groupby 1 countunique 2 collapse 2 < file | 
  awk '$2==1 {n = split($3,a,","); for (i=1;i<=n;i++) print $1, a[i]}'
A T
A T
A T
C F
C F

答え4

sed '
    /\n/D
    :1
    $! {
        N
        /^\(\S\+\s\).*\n\1[^\n]\+$/ b1
    }
    /^\([^\n]\+\n\)\(\1\)\+[^\n]\+$/! D
    h
    s/\n[^\n]\+$//p
    g
    s/.*\n/\n/
    D
    ' file

関連情報