Pass arguments from previous commands (pipes) to awk/printf function and format output

8,201

Solution 1

Following PO's approach, replace awk by Perl -- 'Perl -ae' is very similar to awk...

... | perl -ae ' printf "%-20s %d %s\n", $F[0], $F[1],"▄"x$F[1]'
aa                  12 ▄▄▄▄▄▄▄▄▄▄▄▄
bb                  23 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Edit: with Awk, you could run something along the lines of

... | awk '{printf "%-20s %d %.*s\n",$1,$2,$2,"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄"}'

printf function formats (used in C, Awk, Perl, printf command, etc) can be a little tricky. Following some examples with strings:

  • "%.20s,str - width=max(20,len(str)), align=left
  • "%20s",str - width=max(20,len(str)), align=rigth
  • "%.20s",str - width=min(20,len(str)), truncates if len>20
  • "%20.20s,str - width=20 , truncates if len>20, align=right
  • "%*s",30,str - is printt("%30s",str)
  • "%.*s",30,str - is printt("%.30s",str)

Solution 2

I think you are looking for xargs for the first part. For example:

$ echo foo bar| xargs printf "- %s - %s -\n"
- foo - bar -

To pad and left adjust the output of printf you can do something like:

$ echo foobar 19 | xargs printf '%-30s %s'
foobar                         19

To make certain that the formatting adapts to the longest command name, and to create the bar, you will probably have to write something more complicated that checks the length of the longest argument on the first column, and then doesn't print the results until it has read all the input, for example using awk.

Solution 3

With the help of @JJoao, this is what I came up with later on:

$ history | tr -s ' ' | cut -d ' ' -f3 | sort | uniq -c | sort -nr | head | awk '{ printf "%-25s %-4d", $2, $1, n = $1 / 5; s = sprintf("%*.s", n, ""); gsub(/ /, "◼", s); print s }'
history                   227 ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼
./rebar3                  30  ◼◼◼◼◼◼
cat                       26  ◼◼◼◼◼
cd                        24  ◼◼◼◼
docker                    21  ◼◼◼◼
ps                        20  ◼◼◼◼
bin/erlang_cowboy         19  ◼◼◼
sudo                      13  ◼◼
nix-env                   8   ◼
nix-channel               8   ◼

Not a "big deal", but something I need at work...in case somebody needs it later on.

Share:
8,201

Related videos on Youtube

x80486
Author by

x80486

Denosaur, Gopher — in that order. Erlang deserter 🤣 Web development. Breaking the Internet...one hub at a time. Reading. Thinking. Scuba diving.

Updated on September 18, 2022

Comments

  • x80486
    x80486 over 1 year

    I'm trying to filter the most used commands and print that out in a certain way. So far, I've managed to put the desired "filters":

    $ history | tr -s ' ' | cut -d ' ' -f3 | sort | uniq -c | sort -n | tail | awk '{ printf "%s%20s\n", $2, $1 }'
    

    ...but I can't get the output correctly.

    I would like to be able to display the final output like:

    checkupdates        16 ▄▄▄
    find                16 ▄▄▄
    ./gradlew           17 ▄▄▄
    ./rebar3            21 ▄▄▄▄
    nix-env             24 ▄▄▄▄
    cd                  26 ▄▄▄▄▄
    docker              33 ▄▄▄▄▄▄
    rebar3              43 ▄▄▄▄▄▄▄▄
    sudo                46 ▄▄▄▄▄▄▄▄▄
    flatpak             56 ▄▄▄▄▄▄▄▄▄▄▄
    

    I want to use awk or printf, but I can't figure it out how to format the output. Also, it's tricky to manage the space between the command(s) and the next column (the usage numbers) ‒ the third one is just one space away from the second one.


    PS: The scale for the ▄ can be anything.

  • x80486
    x80486 almost 6 years
    Thanks, but currently I can't use Perl since it is not installed in the server I'm going to run this. I think I'm going to leave out the bars part for the moment. I'll take this solution if nobody chime in with something in bash and/or awk.
  • JJoao
    JJoao almost 6 years
    @ɐuıɥɔɐɯ, please see my edit.
  • x80486
    x80486 almost 6 years
    On the same realm, do you know how to place the value of n in the sprintf function for this command: history | tr -s ' ' | cut -d ' ' -f3 | sort | uniq -c | sort -n | tail | awk '{ printf "%-25s %-4d", $2, $1, n = $1 / 12; s = sprintf("%($n)s", ""); gsub(/ /, "◼", s); print s }'. I did try $(n), but that didn't do anything ;)
  • JJoao
    JJoao almost 6 years
    @ɐuıɥɔɐɯ, awk '{... s=sprintf("%*.s",n,""); ...
  • JJoao
    JJoao almost 6 years
    @ɐuıɥɔɐɯ, Please see my explanation. You should write your answer :) -- if you used sort -nr | head you could use first line to define a "perfect" n.
  • x80486
    x80486 almost 6 years
    Thanks for your help! I like better the sort -nr | head approach...and also, this s = sprintf("%*.s", n, ""); works like a charm! I can't upvote your answer more than once ;)