同じファイルでawkを2回実行する方法

同じファイルでawkを2回実行する方法

user_idを含むログファイルと、コンテスト結果を含む他の列があります。私の考えでは:

  1. すべての勝利したユーザーのuser_idを探す
  2. これらの user_id が与えられると、そのユーザーのすべてのログエントリが返されます。

例:

log.csv

id,user_id,winner,page_id
1,user_1,win,1
2,user_1,,10
3,user_2,,1
4,user_2,,2
5,user_4,win,10
6,user_5,,2
7,user_5,win,3

このようなログファイルがある場合は、現在これを2つのステップに分割します。

ステップ1:「win」という言葉が言及されているすべての行を返します。

/win/ {
    FS=","

    # To make unique, store user_id's in array
    n[$2] = 0
}

# Print the unique array keys
END{
    for (x in n)
        print x
}

これは以下を生成します。

user_1
user_4
user_5

この出力をファイルに保存します。output.txt

次に、そのファイルと元のログファイルを別のawkファイルに渡します。

NR == FNR{
    n[$1] = 0   # Set the user ID to the array
    next        # Go to the next file
}
{
    FS=","
    if($2 in n){
        print $0
    }
}

これは正しい出力を返します(各user_idのすべての勝利行)。

1,user_1,win,1
2,user_1,,10
5,user_4,win,10
6,user_5,,2
7,user_5,win,3

これを行うよりエレガントな方法はありますか?単一のawkファイルを使用しますか?

答え1

遅すぎましたが、子孫のために次のようにできることをお知らせしたいと思います。

awk '
   {
       # do first pass stuff
   }
   
   END
   {
       while(getline < FILENAME)
       {    
           # do second pass stuff
       }
       close(FILENAME)
   }
' file

より多くのパスを実行するには、close(FILENAME)最初のwhileループの後に2番目のループを実行できます。

答え2

2つの配列を使いましょう。

awk -F, '{a[$0]=$2;if($3=="win")b[$2]++}END{for(i in a){if(b[a[i]])print i}}'

答え3

これを行うよりエレガントな方法はありますか?

もちろんです。タイトルで述べたように、同じファイルに対してAwkを2回実行するだけです。

awk -F, '$3=="win"{won[$2]} FNR==NR{next} $2 in won' log.csv log.csv

答え4

私の埋め方はあなたが持っているgrepよりも速いです。awkGNU grepPerl拡張あなたは試すことができます

fgrep -f <(grep -oP "[^,]*(?=,win)" log.csv) log.csv

それ以外の場合は、出力をパイプする必要がperl.extあります。grepcut

fgrep -f <(grep win log.csv | cut -d, -f2) log.csv

または使用してくださいsed(上記より少し速いようですgrep| cut

fgrep -f <(sed -n '/win/s/^[^,]*,\([^,]*\).*/\1/p' log.csv) log.csv

関連情報