UNIX按两个值分组

时间:2019-02-01 14:06:17

标签: bash unix awk sed grep

我有一个包含以下几行的文件(值用“;”分隔):

dev_name;dev_type;soft
name1;ASR1;11.1
name2;ASR1;12.2
name3;ASR1;11.1
name4;ASR3;15.1

我知道如何将它们按一个值进行分组,例如对所有ASRx的计数,但是如何将其按两个值进行分组,例如:

ASR1
    *11.1 - 2
    *12.2 - 1
ASR3 
    *15.1 - 1

6 个答案:

答案 0 :(得分:1)

另一个awk

$ awk -F';' 'NR>1 {a[$2]; b[$3]; c[$2,$3]++} 
             END  {for(k in a) {print k; 
                                for(p in b) 
                                   if(c[k,p]) print "\t*"p,"-",c[k,p]}}' file
ASR1
        *11.1 - 2
        *12.2 - 1
ASR3
        *15.1 - 1

答案 1 :(得分:0)

我不想鼓励懒惰的问题,但是我写了一个解决方案,并且我确定有人可以指出改进之处。我喜欢在这个网站上发布答案,因为我学到了很多东西。 :)

sort的一个二进制子调用,否则所有内置处理。这意味着使用read,这很慢。如果您的文件很大,建议您在awkperl中重写循环,但这可以完成工作。

sed 1d groups |                        # strip the header
  sort -t';' -k2,3 > group.srt         # pre-sort to collect groupings
declare -i ctr=0                       # initialize integer record counter
IFS=';' read x lastA lastB < group.srt # priming read for comparators
printf "$lastA\n\t*$lastB - "          # priming print (assumes at least one record)
while IFS=';' read x a b               # loop through the file
do if [[ "$lastA" < "$a" ]]            # on every MAJOR change
   then printf "$ctr\n$a\n\t*$b - "    # print total, new MAJOR header and MINOR header
        lastA="$a"                     # update the MAJOR comparator
        lastB="$b"                     # update the MINOR comparator
        ctr=1                          # reset the counter
   elif [[ "$lastB" < "$b" ]]          # on every MINOR change
   then printf "$ctr\n\t*$b - "        # print total and MINOR header
        ctr=1                          # reset the counter
   else (( ctr++ ))                    # otherwise increment
   fi
done < group.srt                       # feed read from sorted file
printf "$ctr\n"                        # print final group total at EOF

答案 2 :(得分:0)

尝试类似

awk -F ';' '
   NR==1{next}
   {aRaw[$2"-"$3]++}
   END {
      asorti( aRaw, aVal)
      for( Val in aVal) {
         split( aVal [Val], aTmp, /-/ )
         if ( aTmp[1] != Last ) { Last = aTmp[1]; print Last }
         print "   " aTmp[2] " " aRaw[ aVal[ Val] ]
         }
      }
   ' YourFile

这里的关键是在数组中使用2个字段。 END部分比内容本身更难以呈现值

答案 3 :(得分:0)

使用Perl

$ cat bykub.txt
dev_name;dev_type;soft
name1;ASR1;11.1
name2;ASR1;12.2
name3;ASR1;11.1
name4;ASR3;15.1
$ perl -F";" -lane ' $kv{$F[1]}{$F[2]}++ if $.>1;END { while(($x,$y) = each(%kv)) { print $x;while(($p,$q) = each(%$y)){ print "\t\*$p - $q" }}}' bykub.txt
ASR1
        *11.1 - 2
        *12.2 - 1
ASR3
        *15.1 - 1
$

答案 4 :(得分:0)

"@ionic/angular-toolkit:service": {
  "flat": false
}

或者如果您喜欢管道。...

$ cat tst.awk
BEGIN { FS=";"; OFS=" - " }
NR==1 { next }
$2 != prev { prt(); prev=$2 }
{ cnt[$3]++ }
END { prt() }

function prt(   soft) {
    if ( prev != "" ) {
        print prev
        for (soft in cnt) {
            print "    *" soft, cnt[soft]
        }
        delete cnt
    }
}

$ awk -f tst.awk file
ASR1
    *11.1 - 2
    *12.2 - 1
ASR3
    *15.1 - 1

答案 5 :(得分:0)

还有另一种解决方案,该解决方案使用始终有用的GNU datamash来对组进行计数:

$ datamash -t ';' --header-in -sg 2,3 count 3 < input.txt |
   awk -F';' '$1 != curr { curr = $1; print $1 } { print "\t*" $2 " - " $3 }' 
ASR1
    *11.1 - 2
    *12.2 - 1
ASR3
    *15.1 - 1