4

Supposing I have a log file containing thrown Exceptions:

ExceptionA
loggedFunctionCall
ExceptionB
ExceptionA
loggedFunctionCall
ExceptionD
ExceptionB
loggedFunctionCall
ExceptionB

I want to count the number of occurrences of every different Exception and currently my solution is:

cat file.txt | grep Exception | sort | uniq -c | sort -n

With the result:

      1 ExceptionD
      2 ExceptionA
      3 ExceptionB

However I would like to display count number on the right side and get rid of these indents, so the final effect should look as follows:

ExceptionD 1
ExceptionA 2
ExceptionB 3

I'm looking for a simple solution - preferably without writing any additional bash scripts, just by using pure terminal commands.

1
  • suffix | perl -pe 's/^\s+(\d+) (.*)/\2 \1/' to your current pipeline seems to work
    – user339730
    Dec 5 '20 at 15:40
8

You could use a simple awk command for the whole task:

awk '/Exception/{a[$0]++} END {for (x in a) print x,a[x]}' file | sort -nk2

Output

ExceptionD 1
ExceptionA 2
ExceptionB 3

The order for an awk associative array is undefined, so usually you will need to pipe to sort, k2 means sorting by second field.


Another alternative for sorting is using GNU awk predifined sorting and sort by numerical value, ascending:

awk '/Exception/{a[$0]++} END {
        PROCINFO["sorted_in"] = "@val_num_asc"
        for (x in a) print x,a[x]
    }' file

Also, if you want to keep your existing commands, and to just reverse the position of the two fields, you can modify to:

grep 'Exception' file | sort | uniq -c | awk '{print $2,$1}' | sort -nk2
5
  • Note that awk '{print $2,$1}' only works as long as the matched expressions contain no space.
    – Quasímodo
    Dec 4 '20 at 9:34
  • Yes, this is the case in the example. I noticed you think of the generalization, to print the last field first and the rest of the line following, which could have many good ideas for awk,sed,cut,etc...
    – thanasisp
    Dec 4 '20 at 9:40
  • Indeed, I had proposed awk '{$(NF+1)=$1;$1=""}1', but that mangles spaces. Doing it all in one Awk as you suggest is the most appropriate.
    – Quasímodo
    Dec 4 '20 at 9:44
  • I do wish awk came with more array functionality. perl's handy here: | perl -lane 'push @F, shift @F; print join " ", @F' Dec 4 '20 at 13:16
  • 1
    @glennjackman the problem is you could say that about 100 different things and then you end up with a language that has thousands of constructs/operations instead of one with 20 or so and that leads to zoitz.com/comics/perl_small.png. If people want a language with all those constructs they already have one. Despite the occasional frustration I've really come to appreciate the awk language approach of only providing constructs to do things you can't do easily (even if not tersely) with other existing constructs.
    – Ed Morton
    Dec 4 '20 at 16:57
3

With perl

perl -lne '$h{$_}++ if /Exception/;
           END{print "$_ $h{$_}" for sort {$h{$a} <=> $h{$b}} keys %h}'

sort {$h{$a} <=> $h{$b}} keys %h will sort based on hash value. See https://perldoc.perl.org/functions/keys for details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.