重複リストを削除しますが、その部分をグループ化してください。

重複リストを削除しますが、その部分をグループ化してください。

失敗したログインのいくつかのアクセスルールをコンパイルしており、いくつかのパイピング後に次のような結果が得られました。

cat <<INPUT | sort -k 3,3 --unique
Deny from 13.42.98.142 # demo
Deny from 13.42.98.142 # test
Deny from 13.42.98.142 # user
Deny from 133.142.200.152 # admin
INPUT

ただ注意を引くために試したログイン(最後のフィールド)を維持したいと思います。私のテストコードは次のように出力されます。

Deny from 13.42.98.142 # demo
Deny from 133.142.200.152 # admin

次のような出力を探しています。

Deny from 13.42.98.142 # demo, test, user
Deny from 133.142.200.152 # admin

または、より良い方法は次のとおりです(有効な構文なので.htaccess)。

# demo, test, user
Deny from 13.42.98.142
# admin
Deny from 133.142.200.152

ノート:私が入力したものは今私が作る方法です。私は頑固ではなく、エレガントなソリューションにうまく合うように変更することができます。また、シェルでリストのグループ化を実装する方法に関する一般的な回答も受け入れます。

答え1

これは仕事ですawk

awk -F'#' '
    { a[$1] = (a[$1] ? a[$1] "," $2 : $2) }
    END { for(x in a) print "#" a[x] ORS x }
' file

# admin
Deny from 133.142.200.152 
# demo, test, user
Deny from 13.42.98.142 

print複数の出力形式を取得するには、最後のステートメントを修正してください。レコードの順序はどのキーでもソートされないので、あなたの目的には必要ないようです。

GNU awkを使用してキーごとに(文字列、昇順)ソートする必要がある場合は、次を追加できます。

PROCINFO["sorted_in"] = "@ind_str_asc"

屋根の前にfor。引用:GNU awk配列の並べ替え

答え2

GNUを使用してdatamash最初の#区切り文字フィールドにグループ化し、2番目のフィールドを折りたたみます。

datamash -s -t '#' groupby 1 collapse 2 <<'END_RULES'
Deny from 13.42.98.142 # demo
Deny from 13.42.98.142 # test
Deny from 13.42.98.142 # user
Deny from 133.142.200.152 # admin
END_RULES

この-sオプションは入力データをソートしますが、この場合はソートされているように見えるため、必ずしも必要ではありません。

出力:

Deny from 13.42.98.142 # demo, test, user
Deny from 133.142.200.152 # admin

答え3

どんなawk

awk -v sep=', ' '
    { usr=$NF; sub(/[[:blank:]]*#.*$/, "");
      if(!seen[$0]++) ordr[$0]=++c;
      usrsRec[ordr[$0], $0]=dataRec[$0]= ($0 in dataRec?dataRec[$0] sep:"") usr
    }
END { for(recNr=1; recNr<=c; recNr++)
          for(data in dataRec)
              if((recNr, data) in usrsRec)
                  print "#", usrsRec[recNr, data] ORS data
 }' infile

出力:

# demo, test, user
Deny from 13.42.98.142
# admin
Deny from 133.142.200.152 

関連情報