3

Currently I have this kind of output format:

{ echo "$(figlet buddhi)"; echo "$(figlet lw)"; }
 _               _     _ _     _
| |__  _   _  __| | __| | |__ (_)
| '_ \| | | |/ _` |/ _` | '_ \| |
| |_) | |_| | (_| | (_| | | | | |
|_.__/ \__,_|\__,_|\__,_|_| |_|_|

 _
| |_      __
| \ \ /\ / /
| |\ V  V /
|_| \_/\_/


And I would like to have this output format:

figlet buddhi lw
 _               _     _ _     _   _
| |__  _   _  __| | __| | |__ (_) | |_      __
| '_ \| | | |/ _` |/ _` | '_ \| | | \ \ /\ / /
| |_) | |_| | (_| | (_| | | | | | | |\ V  V /
|_.__/ \__,_|\__,_|\__,_|_| |_|_| |_| \_/\_/

The reason is: I would like to color each name (buddhi, lw) with a different color. But, retain the format of a continuous string, or at maximum space-separated, as above.

Example:

 #COMMANDS CREATED INSIDE /ETC/BASH.BASHRC FILE
 # USING ANSI COLORS
 RED="\e[31m"
 ORANGE="\e[33m"
 BLUE="\e[94m"
 GREEN="\e[92m"
 STOP="\e[0m"


 printf "${GREEN}"
 printf "=================================\n"
 printf "${ORANGE}"
 figlet -f standard "Buddhi"
 printf "${BLUE}"
 figlet -f  small "LW"
 printf "${GREEN}"
 printf "=================================\n"
 printf "${STOP}"
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
BuddhiLW
  • 608
  • 3
  • 9

5 Answers5

5

Store the lines of each word in arrays, output both the arrays line by line. As the first line of "Buddhi" seems to be one character shorter, I stored the longest line length of the first word in a variable, and used the %-s format to pad each line.

#! /bin/bash
RED="\e[31m"
ORANGE="\e[33m"
BLUE="\e[94m"
GREEN="\e[92m"
STOP="\e[0m"

mapfile -t left  < <(figlet -f standard "Buddhi")
mapfile -t right < <(figlet -f small    "LW")

maxlength=0
for line in "${left[@]}" ; do
    if (( ${#line} > maxlength )) ; then
        maxlength=${#line}
    fi
done

printf "${GREEN}"
printf "=================================\n"

for ((i=0; i<=${#left[@]}; ++i)) ; do
    printf "${ORANGE}%-${maxlength}s ${GREEN}%s\n" "${left[i]}" "${right[i]}"
done

printf "${GREEN}"
printf "=================================\n"
printf "${STOP}"
choroba
  • 231,213
  • 25
  • 204
  • 289
2

In lieu of figlet I'll use the following as my inputs:

$ cat buddhi
 _               _     _ _     _
| |__  _   _  __| | __| | |__ (_)
| '_ \| | | |/ _` |/ _` | '_ \| |
| |_) | |_| | (_| | (_| | | | | |
|_.__/ \__,_|\__,_|\__,_|_| |_|_|

$ cat lw
 _
| |_      __
| \ \ /\ / /
| |\ V  V /
|_| \_/\_/

Assuming figlet generates the same number of output lines for each input string, we can use paste (@ as a delimiter) and a while/read loop to generate the desired output:

printf "${GREEN}"
printf "============================\n"

maxwidth=$(awk '{max=length($0) > max ? length($0) : max}END{print max}' buddhi)

while IFS='@' read -r col1 col2
do
    printf "${ORANGE}%-*s ${BLUE}%s\n" "${maxwidth}" "${col1}" "${col2}"
done < <(paste -d"@" buddhi lw)

printf "${GREEN}"
printf "============================\n"

This generates:

enter image description here


Expanding to 3 input streams:

printf "${GREEN}"
printf "============================\n"

max1=$(awk '{max=length($0) > max ? length($0) : max}END{print max}' buddhi)
max2=$(awk '{max=length($0) > max ? length($0) : max}END{print max}' lw)

while IFS='@' read -r col1 col2 col3
do
    printf "${ORANGE}%-*s ${BLUE}%-*s ${RED}%s\n" "${max1}" "${col1}" "${max2}" "${col2}" "${col3}"
done < <(paste -d"@" buddhi lw buddhi)

printf "${GREEN}"
printf "============================\n"

This generates:

enter image description here

markp-fuso
  • 28,790
  • 4
  • 16
  • 36
1

If you need a shorter version:

printf "$GREEN=================================\n"
{ figlet Buddhi; echo 'EOF'; figlet LW; } | awk 'NF==1&&$1=="EOF" {noskip=1; next; } noskip==0 { f[++c]=$0; next; } { printf "%s%s%s%s\n","'"$ORANGE"'",f[++k],"'"$BLUE"'",$0;}'
printf "$GREEN=================================\n"
tput sgr0

I would recommend to use tput for setting the color as not every terminal will know your escape sequences

Tuxinose
  • 184
  • 4
  • I get the error : ```awk: cmd. line:1: warning: escape sequence `\e' treated as plain `e'``` – BuddhiLW Dec 21 '21 at 17:28
  • Don't let shell variables expand to become part of the body of an awk script, see [how-do-i-use-shell-variables-in-an-awk-script](https://stackoverflow.com/questions/19075671/how-do-i-use-shell-variables-in-an-awk-script). – Ed Morton Dec 21 '21 at 17:31
  • Ed - you are right. It was only a quick hack. On my terminal it works :-) – Tuxinose Dec 23 '21 at 00:58
1

The guys who invented shell also invented awk for shell to call to manipulate text. Those escape sequences don't change colors on my terminal, they just show up as-is (fortunately so you can see where the script is puting them):

$ cat tst.sh
#!/usr/bin/env bash

awk '
    BEGIN {
        red =    "\\e[31m"
        orange = "\\e[33m"
        blue =   "\\e[94m"
        green =  "\\e[92m"
        stop =   "\\e[0m"
    }
    {
        val[(NR==FNR),FNR] = $0
    }
    NR == FNR {
        wid = length($0)
        maxWid = ( wid > maxWid ? wid : maxWid )
    }
    END {
        for ( lineNr=1; lineNr<=FNR; lineNr++ ) {
            printf "%s%-*s%s%s%s\n", orange, maxWid, val[1,lineNr], blue, val[0,lineNr], stop
        }
    }
' <(cat Buddhi) <(cat LW)

$ ./tst.sh
\e[33m _               _     _ _     _ \e[94m _\e[0m
\e[33m| |__  _   _  __| | __| | |__ (_)\e[94m| |_      __\e[0m
\e[33m| '_ \| | | |/ _` |/ _` | '_ \| |\e[94m| \ \ /\ / /\e[0m
\e[33m| |_) | |_| | (_| | (_| | | | | |\e[94m| |\ V  V /\e[0m
\e[33m|_.__/ \__,_|\__,_|\__,_|_| |_|_|\e[94m|_| \_/\_/\e[0m

Since I don't have figlet, I ran the above on these files:

$ head Buddhi LW
==> Buddhi <==
 _               _     _ _     _
| |__  _   _  __| | __| | |__ (_)
| '_ \| | | |/ _` |/ _` | '_ \| |
| |_) | |_| | (_| | (_| | | | | |
|_.__/ \__,_|\__,_|\__,_|_| |_|_|

==> LW <==
 _
| |_      __
| \ \ /\ / /
| |\ V  V /
|_| \_/\_/

Just change the last line of the script from:

' <(cat Buddhi) <(cat LW)

to

' <(figlet Buddhi) <(figlet LW)

to use actual figlet output.

the above assumes you only have 2 figlet output strings to concatenate and that both sets of output are the same length, it's easy tweaks if either of those assumptions is wrong.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • Cool but quite hard for beginners – Ivan Dec 21 '21 at 19:57
  • 1
    @Ivan let me know what you find difficult to understand about it and I'll be happy to explain it. To me it seems easier to understand than the currently accepted answer or most, if not all, of the others (all of which, I think, fall into the "hard for beginners" category!) and it's the most efficient and robust answer and most portable as it'll work using any awk in any shell if you just replace those `<(..)` constructs by creating temp files. – Ed Morton Dec 21 '21 at 20:00
  • these special vars(NR,FNR) and all this magic `val[(NR==FNR),FNR] = $0` and `NR == FNR` – Ivan Dec 21 '21 at 20:54
  • 1
    @Ivan `FNR` is the current line number while reading the current file, `NR` is the line number across all input files. `NR==FNR` is testing if this is the first file or the 2nd one and using it as the first part of a compound index for the array `va[]` is just a way to populate `val[]` line by line for both input files so you get `val[0,1]` holding line1 of the first file read and `val[1,1]` holding line1 of the 2nd file read. – Ed Morton Dec 21 '21 at 21:28
  • 1
    Writing `val[(NR==FNR),FNR] = $0` in awk is like writing `val[((NR==FNR))","$FNR]="$line"` in shell as part of a code snippet like `declare -A val; NR=0; FNR=0; while IFS= read -r line; do (( NR++ )); (( FNR++ )); val[((NR==FNR))","$FNR]="$line"; done < file1; FNR=0; while IFS= read -r line; do (( NR++ )); (( FNR++ )); val[((NR==FNR))","$FNR]="$line"; done < file2` where the rest of that code is part of what awk always does for you when reading input. – Ed Morton Dec 21 '21 at 21:28
  • 1
    See https://www.gnu.org/software/gawk/manual/gawk.html#Records for a definition of `NR` and `FNR` and more info on what awk does as it reads input if you care. – Ed Morton Dec 21 '21 at 21:34
  • 1
    Awk is really powerful thing, thank you for the explanation. – Ivan Dec 22 '21 at 05:25
1

Using coordinates

#!/bin/bash

RED='\e[31m'
GRN='\e[32m'

XY(){ printf "\e[$2;${1}H$3"; }

mapfile -t frst < <(figlet -f standard "Buddhi")
mapfile -t scnd < <(figlet -f small    "LW")

XY 1 1 "$GRN==============================================="; y=2
for line in "${frst[@]}"; { XY 0  $y "$RED$line"; ((y++)); }; y=2
for line in "${scnd[@]}"; { XY 35 $y "$GRN$line"; ((y++)); }
XY 1 8 "$GRN==============================================="

enter image description here

More examples here, here and here

Ivan
  • 6,188
  • 1
  • 16
  • 23