awk or sed: change the color of a column w/o screwing up column spacing

Hey folks. I wrote a little awk script that summarizes /proc/net/dev info and then pipes it to the nix column command to set up column spacing appropriately.

Here's some example output:

  Iface   RxMBytes  RxPackets  RxErrs  RxDrop  TxMBytes  TxPackets  TxErrs  TxDrop
  bond0   9         83830      0       0       12        62866      0       0
  eth0    1         18689      0       0       0         0          0       0
  eth1    0         0          0       0       0         0          0       0
  eth2    0         0          0       0       0         0          0       0
  eth3    8         65141      0       0       12        62866      0       0
  eth4    1         12949      0       0       0         375        0       0
  eth5    0         0          0       0       0         0          0       0
  virbr0  0         0          0       0       0         22         0       0

I'd like to colorize the output as well -- it's easy enough to change the color of the header line, but the other piece I can't figure out is: changing the color of the interface name, i.e., the first field of line 2+.

Now, in a perfect world I would have my awk script generate the color and columnize the output but I haven't tried to figure out columnizing in awk yet -- it doesn't look easy. Here's what I did to colorize the first line:

the_above_output | awk -vC0='\033[0;0m' -vC1='\033[1;35m' '
  { if (NR == 1) print C1 $0 C0; else print }'

This won't work for the additional lines (i.e. the ones where I just want to change the color of $1), because as soon as I start picking out fields, I'll lose the carefully-crafted whitespace separating said fields.

I think sed is what I need... I suspect with the right switches it should be able to

  • operate on NR >= 2
  • regex replace the first word of each record with <color>&<color>

Any ideas will be greatly appreciated.

PS: I have an application I'm working on that uses tons of awk "modules" to do this kind of parsing of output. Some of them also pipe their output to column for the final display as well. If you know of any good resources on awk columnizing, I'd love to see 'em. Here's another example:

ETHTOOL
  eth0  link=UP 1000Mb/s full (autoneg=Y)  drv bnx2 v2.1.11 / fw bc
  eth1  link=DOWN                          drv bnx2 v2.1.11 / fw bc
  eth2  link=DOWN                          drv e1000e v1.4.4-k / fw 5.11-2
  eth3  link=UP 1000Mb/s full (autoneg=Y)  drv e1000e v1.4.4-k / fw 5.11-2
  eth4  link=UP 1000Mb/s full (autoneg=Y)  drv e1000e v1.4.4-k / fw 5.11-2
  eth5  link=DOWN                          drv e1000e v1.4.4-k / fw 5.11-2

That's generated by 2 awk commands piped to column. And currently, after that I pipe it to another awk to change the color of each line -- orange if the link is down and green if it's up. I'm happy with that, but I might prefer to change just the link=DOWN or link=UP part -- but again, I don't see how to do it without screwing up the spacing.

---------- Post updated at 06:20 AM ---------- Previous update was at 02:54 AM ----------

I spent a few hours working on other things and then it just hit me -- I could use awk's gensub() for this. I'd still love to learn more about awk columnizing, but ....

 the_above_proc/net/dev_output |
  awk  -vC0='\033[0;0m' -vC1='\033[1;35m' -vC2='\033[0;34m' '
    {
      if (NR == 1) print C1 $0 C0
      else printf gensub(/(^  [[:graph:]]+ )/, C2"\\1"C0, 1)"\n"
    }'

You could also use sed to insert a column separator (comma in this case) and then use sort of your first awk cmd:

sed 's/  */&,/g' test| awk -vC0='\033[0;0m' -vC1='\033[1;35m' '
  { if (NR == 1) {$1=$1;$0=C1$0C0} else $1=C1$1C0; print }' FS=","
1 Like

You can do it all in one awk. You know the size of your fixed-width columns, you use printf() . example

printf("%s%-10s%s ...", C1, intf, C0, ...)

or I guess hardcode the colors into the format string.. ideally you'd use tput to extract the proper information for the terminal rather though.

I don't think the col width is known in advance, in above example it ranges from 6 to 8, and even the header would not be a reliable indicator as you see in the Iface col. column does a fine job here, and it is not that easy to keep the col alignment intact.