删除重复列表,但对其部分进行分组

删除重复列表,但对其部分进行分组

我正在从失败的登录中编译一些访问规则,经过一些管道处理后,我得到了以下结果:

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

笔记:输入的内容就是我现在的制作方式 - 我并不固执,如果它更适合优雅的解决方案,我可以更改它。我还将接受如何在 shell 中实现列表分组的一般答案。

答案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

使用 GNUdatamash按第一个#分隔字段进行分组并折叠第二个字段:

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 

相关内容