Search code examples
awkcolorsterminalprintftabular

Bash - Number color based on sign, tabbed


I have lines like these in the terminal

8  XLM      3.85  -10.18  -32.94   0.00003836      0.564      0.470    8.402
9  MIOTA   -0.60   -3.38  -11.22    0.0002438      3.582      2.986    8.300
10 DASH     0.55   -2.01   -6.55    0.0742421   1090.820    909.358    7.102
11 NEO     -0.40   -0.88   27.09   0.00832249    122.280    101.938    6.626
12 TRX      7.33  -18.68   42.45   0.00000791      0.116      0.097    6.369

and I would like to print the 3,4,5 fields in green if they're positive or in red if they're negative. I'm using awk and printf but cannot have both color and correct tabbing with printf.

If I add color codes with awk like

awk '{ if($3<0){$3="\033[0;31m"sprintf("%.2f",$3)"\033[0;0m"} else {$3="\033[0;32m"sprintf("%.2f",$3)"\033[0;0m"};}1'

then the tabbing is lost or messed up.

The full command without colors is

curl -s "https://api.coinmarketcap.com/v1/ticker/?convert=EUR&limit=20" | jq -r '.[] | [.rank, .symbol, .percent_change_1h, .percent_change_24h, .percent_change_7d, .price_btc, .price_usd, .price_eur, .market_cap_eur] | @tsv' | awk '{ $3=sprintf("%.2f",$3); $4=sprintf("%.2f",$4); $5=sprintf("%.2f",$5); $6=sprintf("%.8f",$6); $7=sprintf("%.2f",$7); $8=sprintf("%.2f",$8); $9=sprintf("%.3f",$9/(1*10^9)) }1' | xargs printf '%2s %-5s %7s %7s %7s %12s %10s %10s %8s\n' 'r' 'curr' '1d' '24h' '7d' 'btc' 'usd' 'eur' 'mcap B'

Solution

  • Your field spacing is getting modified because you're modifying a field which causes awk to recompile the record replacing input spaces (IFS) with OFS values. If you change the whole record instead of any individual field then awk won't change the spacing between fields:

    With GNU awk for gensub():

    $ cat tst.awk
    BEGIN { red="\033[0;31m"; green="\033[0;32m"; norm="\033[0;0m" }
    {
        for (i=3; i<=5; i++) {
            $0 = gensub("(([^[:space:]]+[[:space:]]+){"i-1"})([^[:space:]]+)", "\\1" ($i < 0 ? red : green) "\\3" norm,1)
        }
        print
    }
    

    or with any awk:

    $ cat tst.awk
    BEGIN { red="\033[0;31m"; green="\033[0;32m"; norm="\033[0;0m" }
    {
        for (i=3; i<=5; i++) {
            sub("([^[:space:]]+[[:space:]]+){"i-1"}", "&" ($i < 0 ? red : green))
            sub("([^[:space:]]+[[:space:]]+){"i-1"}[^[:space:]]+", "&" norm)
        }
        print
    }
    
    $ awk -f tst.awk file
    8  XLM      3.85  -10.18  -32.94   0.00003836      0.564      0.470    8.402
    9  MIOTA   -0.60   -3.38  -11.22    0.0002438      3.582      2.986    8.300
    10 DASH     0.55   -2.01   -6.55    0.0742421   1090.820    909.358    7.102
    11 NEO     -0.40   -0.88   27.09   0.00832249    122.280    101.938    6.626
    12 TRX      7.33  -18.68   42.45   0.00000791      0.116      0.097    6.369
    

    and so you can see the colors:

    enter image description here