最初の列が一意の行のみを印刷する

最初の列が一意の行のみを印刷する

リストをソートし、最初の列が一度だけ表示されるすべての行を印刷する方法を探しています。つまり、最初の列でのみ一致します。たとえば、最初の列がパスで、2番目の列に「type」を含むファイルがあります。

/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy

(実際のファイルのソートは -k1,1 です)

それでは、次のような状況を抽出したいと思います。

/path/foo/X barsy
/path/foo/Y footsy

以前の行を保存し、前の行の最初のフィールドを現在の行の対応するフィールドと比較する必要があるawkを使用する方法を考えています。しかし、まだ何をすべきかわかりません。 :(他の質問で見つけた解決策を適用しようとしましたが、実際には望みどおりに機能しませんでした。

awk '{
  prev=$0; path=$1; type=$2
  getline
  if ($1 != $path) {
    print prev
  }
}'

答え1

これらの回答には入力ソートは必要ありません。

数と最後の行を配列に保存します。大容量ファイルには多くのメモリが必要で、GNU awkが必要です。

gawk '
    {count[$1]++; line[$1]=$0} 
    END {
        PROCINFO["sorted_in"]="@val_str_asc"
        for (key in line) if (count[key] == 1) print line[key]
    }
' file

ファイルを2回スキャンし、最初に数を取得し、次に1に行を印刷します。

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

ソートされた入力を活用するには、最速で最小限のメモリが必要です。

awk '
    prev_key && prev_key != $1 {if (count==1) print prev_line; count=0}
    {prev_key=$1; prev_line=$0; count++}
    END {if (count==1) print prev_line}
' file

答え2

  1. awk通常、各入力行を読み取り、その行のスクリプトが呼び出されます。あなたがそれを使用する状況はgetlineほとんどありません。以下は、6行の入力でスクリプトを実行したときに何が起こるのかについての概要です。

    最初の行を正常に読んでください


    Call変数を設定しgetline、2行を読み取り
    、変数を比較します。

    3行目を正常に読んでください


    Call変数を設定し、getline行4を読み、
    変数を比較します。

    5行目を正常に読んでください


    Call変数を設定し、getline行6を読み、
    変数を比較します。

    明らかにこれはうまくいきません。

  2. 第二に、コードでよく見られる間違いを犯していますawk。のawk入力のフィールドは次に参照され、変数は次に参照されます。$numbervariable_name。これは、コマンドラインパラメータがとして引用され、変数がとして引用されるシェルスクリプトとは異なります。あなたのテスト$number$variable_name

    if ($1 != $path)
    

    しなければならない

    if ($1 != path)
    
  3. 全体的なアプローチに欠陥があります。一度に2行を見ると、ファイルに一度だけ表示される文字列を識別できません。私は一度に3つの行を見ながらこれを行うことができると思います(例:二つ変数の最初の数行)しかし、それらは複雑で混乱しています。発生回数を計算する方が簡単な場合があります。これを行うには、スクリプトを最小限に変更する必要があります。

    awk '{
      if ($1 != path) {
        if (count == 1) {
          print prev
        }
        count=1
      }
      else count++
      prev=$0; path=$1
    }
    END {
        if (count == 1) {
          print prev
        }
    }'
    

    type使用したことがないので削除しました。

    公開:これは本質的にGlennの答えの最後の部分と同じです。

答え3

シェルがサポートしている場合プロセスの交換、スペースやタブを含めないでくださいXY

$ grep -Ff <(awk '{print $1" "}' <file | LC_ALL=C uniq -u) <file
/path/foo/X barsy
/path/foo/Y footsy

答え4

以下を試してみてください。

cat text.tx | sort | uniq -c -w11 | fgrep '1 /' | awk '{print $2" "$3}'

あなたのtext.txtは次のとおりです

]#cat text.txt
/path/foo/1 footsy
/path/foo/1 barsy
/path/foo/X barsy
/path/bar/2 footsy
/path/bar/2 barsy
/path/foo/Y footsy

関連情報