フィールドと部分文字列を抽出し、ソートされた行をマージします。

フィールドと部分文字列を抽出し、ソートされた行をマージします。

タブで区切られた5つのフィールドで構成されるファイルがあります(この場合、無関係のフィールドは空白です)。

1       2       URL                     email               5

                https://www.a.com/t     [email protected]
                https://www.a.com       [email protected]
                https://www.b.fr        [email protected]
                https://www.b.fr/s/faq  [email protected]

希望の出力:

domain          email(s)    
        
a.com           [email protected]
b.fr            [email protected], [email protected]

スピード:

  1. 列3と4を分離します。
awk -F "\t" '{print $3 "\t\t" $4}' 

これにより、上記の最初のブロックに示された内容が生成されます。

どうやって進めますか?

私はフィールドをgrepする方法だけを知っていますが、フィールドを分離することはあなたが望む出力ラインを得るのにあまり役に立ちません。

私はこれに限定されずawk、(フラグを介して)フィールドを簡単に分離できる私が知っている唯一のツールです-F

答え1

awkGNUの使用datamash:

awk 'BEGIN{ OFS=FS="\t" }
  NR>2{                       # skip first two records
    split($3, a, "/" )        # split $3 into array a on /
    domain=a[3]               # 3rd element is the domain name
    sub(/^www\./, "", domain) # remove www. prefix
    print domain, $4          # print domain and email
  }
' file | datamash -g 1 unique 2

このawkセクションでは、最初の2行をスキップし、すべての履歴のドメインと電子メールを印刷します。これは〜になります

a.com   [email protected]
a.com   [email protected]
b.fr    [email protected]
b.fr    [email protected]

その後、出力はdatamash最初のフィールドにパイプされ、入力をグループ化し、2番目のフィールドの固有値のカンマ区切りリストを印刷します。

出力:

a.com   [email protected]
b.fr    [email protected],[email protected]

タイトル行は練習用に予約されています。

答え2

GNU awkを使用して配列の配列合計を処理しますgensub()

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR>1 { d2e[gensub(/[^.]+\.([^.]+\.[^./]+).*/,"\\1",1,$3)][$4] }
END {
    print "domain", "emails(s)"
    for (domain in d2e) {
        cnt = 0
        for (email in d2e[domain]) {
            row = (cnt++ ? row ", " : domain OFS) email
        }
        print row
    }
}

$ awk -f tst.awk file
domain  emails(s)
a.com   [email protected]
b.fr    [email protected], [email protected]

答え3

使用ミラー(sedの助けを借りて):

$ mlr --prepipe 'sed "/^$/d"' --tsv   put -q -S '
  $domain = joinv(mapexcept(splitnvx(joinv(mapselect(splitnvx($URL,"/"),3),""),"."),1),".");
  @e[$domain] = mapsum(@e[$domain],{$email:1});
  end {
    for(k,v in @e){@{email(s)}[k] = joink(v,",")};
    emit @{email(s)}, "domain"
  }' File.tsv
domain  email(s)
a.com   [email protected]
b.fr    [email protected],[email protected]

sed--prepipeコマンドは、入力をTSVに解析できるように、不要な空行を削除します。変数$domainは、URLフィールドを最初に/(3番目の要素を選択)分割し、次に.(最初の要素を除くすべての要素を選択する、たとえばwww)2回分割することによって取得されます。その後、ストリーム外部マッピングは次@eのように構成されます。地図フィールド数email- 同じドメインから重複した電子メールを削除する手順。でendメールマップをコンマ区切り文字列に変換してエクスポートします。

答え4

この問題は、3番目のフィールド(実際にはその一部)をキーとして使用し、4set番目のフィールドを含む対応する値を使用して辞書を設定することで解決できます。 aの有用性setは、要素を本質的に一意に保つため、値を一意に保つためにどのようなプログラミング練習にも努力する必要がないことです。

python3 -c 'import sys
ifile = sys.argv[1]
fs = ofs = "\t"
d = {}

with open(ifile) as fh:
  for i,l in enumerate(fh,1):
    if i < 3: continue
    x,x,y,email,x = l.split(fs)
    domain = y.split("/")[2].split(".",1)[1]
    if domain in d:
      d[domain].add(email)
    else:
      d[domain] = { email }

print(f"domain{ofs}email(s)",
      *[k+ofs+", ".join(v) for k,v in d.items()],
      sep="\n")
' file
domain  email(s)
a.com   [email protected]
b.fr    [email protected], [email protected]

関連情報