UNIX组由两个值

问题描述 投票:0回答:6

我有如下的文件(值由“;”分隔):

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
bash unix awk sed grep
6个回答
0
投票
$ 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

如果你喜欢管道....

$ tail +2 file | cut -d';' -f2- | sort | uniq -c |
    awk -F'[ ;]+' '{print ($3!=prev ? $3 ORS : "") "    *" $4 " - " $2; prev=$3}'
ASR1
    *11.1 - 2
    *12.2 - 1
ASR3
    *15.1 - 1

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

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场。端部更加难以呈现比内容本身的值


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
$

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

0
投票

我不想鼓励偷懒的问题,但我写了一个解决方案,我敢肯定有人能说出改进。我喜欢,因为我学到了很多张贴在本网站的答案。 :)

一个二进制subcall到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
© www.soinside.com 2019 - 2024. All rights reserved.