I am trying to write a coloured output library for bash with various styling options allowing colouring and styling using redirection.
e.g.
echo "Red" | red
outputs red text
and
echo "Bold" | bold
outputs bold text
and
echo "Yellow bold" | yellow | bold
outputs bold yellow text
The code I wrote so far is as follows:
#shellcheck shell=bash
# set debug
# set -o xtrace
# number of colors supported
__colors=$(tput colors 2> /dev/null)
# colors
__black="$(tput setaf 0)"
__red="$(tput setaf 1)"
__green="$(tput setaf 2)"
__yellow="$(tput setaf 3)"
__blue="$(tput setaf 4)"
__magenta="$(tput setaf 5)"
__cyan="$(tput setaf 6)"
__white="$(tput setaf 7)"
# style
__default="$(tput sgr0)"
__bold="$(tput bold)"
__underline="$(tput smul)"
function has_colors() {
COLOR=${COLOR:-auto}
if [[ $COLOR = 'never' ]]; then
return 1
elif [[ $COLOR = 'always' ]]; then
return 0
else
# check if stoud is terminal and terminal supports colors
[[ -t 1 ]] && \
[[ -n $__colors ]] && \
[[ $__colors -ge 8 ]]
fi
}
function __style() {
read -r input
if has_colors; then
echo -e "$1" "$input" "$__default"
else
echo -e "$input"
fi
}
function black() {
__style "$__black"
}
function red() {
__style "$__red"
}
function green() {
__style "$__green"
}
function yellow() {
__style "$__yellow"
}
function blue() {
__style "$__blue"
}
function magenta() {
__style "$__magenta"
}
function cyan() {
__style "$__cyan"
}
function white() {
__style "$__white"
}
function bold() {
__style "$__bold"
}
function underline() {
__style "$__underline"
}
Setting COLOR=always outputs with escape codes all the time. On the other hand COLOR=auto preforms some checks to make sure current stdout is the terminal and terminal supports colors.
The problem is using multiple styling options does not seem to be working.It always applies the last styling option. For example:
echo "Yellow bold" | yellow | bold
outputs bold text, but not yellow.
On the other hand:
echo "Bold yellow" | bold | yellow
outputs yellow text, but not bold.
Funny thing is; setting COLOR=always seems to be working just fine. So it looks like the test I perform to see if stdout is terminal [[ -t 1 ]]
is causing this. I am not sure if it is because there is some kind of delay with that test. But when I remove [[ -t 1 ]]
bit, it works.
Any idea how I can achieve this ? Not expert with Bash or how shell works for that matter. Quite confused here.