bashfunctionprintfansi-escapeansi-colors

printf escape code not formatting in Bash script


I've recently started playing around with Bash, mostly using it to customize my .profile, and I've ran into an issue with the printf command.

In my scripts folder, I have an associative array set up for easy use of ANSI colour codes:

#!/usr/bin/env bash

declare -A fcolors=( 
[black]='\e[30m' 
[red]='\e[31m' 
[green]='\e[32m' 
[yellow]='\e[33m' 
[blue]='\e[34m' 
[magenta]='\e[35m' 
[cyan]='\e[36m' 
[gray]='\e[90m' 
# LIGHT COLOURS
[lgray]='\e[37m' 
[lred]='\e[91m' 
[lgreen]='\e[92m' 
[lyellow]='\e[93m' 
[lblue]='\e[94m' 
[lmagenta]='\e[95m' 
[lcyan]='\e[96m' 
[white]='\e[97m' 
[default]='\e[0m' )

I also, in yet another file, have a script to center output on the terminal, which, admittedly, I borrowed from someone's guide on GitHub:

#!/usr/bin/env bash

# original script by TrinityCoder

# USAGE: printcen "center text" "filler text"

function printcen {
        [[ $# == 0 ]] && return 1

        declare -i TERM_COLS="$(tput cols)"
        declare -i str_len="${#1}"
        [[ $str_len -ge $TERM_COLS ]] && {
                echo "$1";
                return 0;
        }

        declare -i filler_len="$(( (TERM_COLS - str_len) / 2 ))"
        [[ $# -ge 2 ]] && ch="${2:0:1}" || ch =" "
        filler=""
        for (( i = 0; i < filler_len; i++ )); do
                filler="${filler}${ch}"
        done

        printf "%s%s%s" "$filler" "$1" "$filler"
        [[ $(( (TERM_COLS - str_len) % 2 )) -ne 0 ]] && printf "%s" "$ch"
        printf "\n"

        return 0
}

And, finally, I have the line itself that's causing the issue. I've only tried this with this one line, so here it is:

#!/usr/bin/env bash

source ~/.scripts/bagcolors
source ~/.scripts/printcen

printcen " ${fcolors[cyan]} ----========================---- ${fcolors[default]}" " "

When I run the file, the printcen function seems to just print the colour codes exactly, including the escape sequence, as if it were just a regular string. So far, I've tried putting spaces between the colour codes and the text itself, but that didn't seem to change anything.

Any help with this would be appreciated.


Solution

  • The problem with your approach is that you'll be counting invisible chars as part of the string.

    Do this (after you fix the escape sequences as indicated by @gniourf_gniourf)

    l=$(printcen '----========================----')
    printf '%s%s%s\n' "${fcolors[cyan]}" "$l" "${fcolors[default]}"